• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "content/test/net/url_request_prepackaged_interceptor.h"
6 
7 #include "base/file_util.h"
8 #include "base/threading/sequenced_worker_pool.h"
9 #include "base/threading/thread_restrictions.h"
10 #include "content/public/browser/browser_thread.h"
11 #include "net/url_request/url_request.h"
12 #include "net/url_request/url_request_file_job.h"
13 #include "net/url_request/url_request_filter.h"
14 #include "net/url_request/url_request_interceptor.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 
17 using content::BrowserThread;
18 
19 namespace content {
20 
21 namespace {
22 
23 class URLRequestPrepackagedJob : public net::URLRequestFileJob {
24  public:
URLRequestPrepackagedJob(net::URLRequest * request,net::NetworkDelegate * network_delegate,const base::FilePath & file_path)25   URLRequestPrepackagedJob(net::URLRequest* request,
26                            net::NetworkDelegate* network_delegate,
27                            const base::FilePath& file_path)
28       : net::URLRequestFileJob(
29             request, network_delegate, file_path,
30             content::BrowserThread::GetBlockingPool()->
31                 GetTaskRunnerWithShutdownBehavior(
32                     base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)) {}
33 
GetResponseCode() const34   virtual int GetResponseCode() const OVERRIDE { return 200; }
35 
36  private:
~URLRequestPrepackagedJob()37   virtual ~URLRequestPrepackagedJob() {}
38 
39   DISALLOW_COPY_AND_ASSIGN(URLRequestPrepackagedJob);
40 };
41 
42 }  // namespace
43 
44 class URLRequestPrepackagedInterceptor::Delegate
45     : public net::URLRequestInterceptor {
46  public:
Delegate(const std::string & scheme,const std::string & hostname)47   Delegate(const std::string& scheme, const std::string& hostname)
48     : scheme_(scheme), hostname_(hostname), hit_count_(0) {}
~Delegate()49   virtual ~Delegate() {}
50 
Register()51   void Register() {
52     net::URLRequestFilter::GetInstance()->AddHostnameInterceptor(
53         scheme_, hostname_,
54         scoped_ptr<net::URLRequestInterceptor>(this));
55   }
56 
Unregister(const std::string & scheme,const std::string & hostname)57   static void Unregister(
58       const std::string& scheme,
59       const std::string& hostname) {
60     net::URLRequestFilter::GetInstance()->RemoveHostnameHandler(scheme,
61                                                                 hostname);
62   }
63 
64   // When requests for |url| arrive, respond with the contents of |path|. The
65   // hostname and scheme of |url| must match the corresponding parameters
66   // passed as constructor arguments.
SetResponse(const GURL & url,const base::FilePath & path,bool ignore_query)67   void SetResponse(const GURL& url,
68                    const base::FilePath& path,
69                    bool ignore_query) {
70     CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
71     // It's ok to do a blocking disk access on this thread; this class
72     // is just used for tests.
73     base::ThreadRestrictions::ScopedAllowIO allow_io;
74     EXPECT_TRUE(base::PathExists(path));
75     if (ignore_query) {
76       ignore_query_responses_[url] = path;
77     } else {
78       responses_[url] = path;
79     }
80   }
81 
82   // Returns how many requests have been issued that have a stored reply.
GetHitCount() const83   int GetHitCount() const {
84     base::AutoLock auto_lock(hit_count_lock_);
85     return hit_count_;
86   }
87 
88  private:
89   typedef std::map<GURL, base::FilePath> ResponseMap;
90 
91   // When computing matches, this ignores the query parameters of the url.
MaybeInterceptRequest(net::URLRequest * request,net::NetworkDelegate * network_delegate) const92   virtual net::URLRequestJob* MaybeInterceptRequest(
93       net::URLRequest* request,
94       net::NetworkDelegate* network_delegate) const OVERRIDE {
95     CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
96     if (request->url().scheme() != scheme_ ||
97         request->url().host() != hostname_) {
98       return NULL;
99     }
100 
101     ResponseMap::const_iterator it = responses_.find(request->url());
102     if (it == responses_.end()) {
103       // Search for this request's url, ignoring any query parameters.
104       GURL url = request->url();
105       if (url.has_query()) {
106         GURL::Replacements replacements;
107         replacements.ClearQuery();
108         url = url.ReplaceComponents(replacements);
109       }
110       it = ignore_query_responses_.find(url);
111       if (it == ignore_query_responses_.end())
112         return NULL;
113     }
114     {
115       base::AutoLock auto_lock(hit_count_lock_);
116       ++hit_count_;
117     }
118 
119     return new URLRequestPrepackagedJob(request,
120                                         network_delegate,
121                                         it->second);
122   }
123 
124   const std::string scheme_;
125   const std::string hostname_;
126 
127   ResponseMap responses_;
128   ResponseMap ignore_query_responses_;
129 
130   mutable base::Lock hit_count_lock_;
131   mutable int hit_count_;
132 
133   DISALLOW_COPY_AND_ASSIGN(Delegate);
134 };
135 
136 
URLRequestPrepackagedInterceptor(const std::string & scheme,const std::string & hostname)137 URLRequestPrepackagedInterceptor::URLRequestPrepackagedInterceptor(
138     const std::string& scheme,
139     const std::string& hostname)
140     : scheme_(scheme),
141       hostname_(hostname),
142       delegate_(new Delegate(scheme, hostname)) {
143   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
144                           base::Bind(&Delegate::Register,
145                                      base::Unretained(delegate_)));
146 }
147 
~URLRequestPrepackagedInterceptor()148 URLRequestPrepackagedInterceptor::~URLRequestPrepackagedInterceptor() {
149   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
150                           base::Bind(&Delegate::Unregister,
151                                      scheme_,
152                                      hostname_));
153 }
154 
SetResponse(const GURL & url,const base::FilePath & path)155 void URLRequestPrepackagedInterceptor::SetResponse(
156     const GURL& url,
157     const base::FilePath& path) {
158   CHECK_EQ(scheme_, url.scheme());
159   CHECK_EQ(hostname_, url.host());
160   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
161                           base::Bind(&Delegate::SetResponse,
162                                      base::Unretained(delegate_), url, path,
163                                      false));
164 }
165 
SetResponseIgnoreQuery(const GURL & url,const base::FilePath & path)166 void URLRequestPrepackagedInterceptor::SetResponseIgnoreQuery(
167     const GURL& url,
168     const base::FilePath& path) {
169   CHECK_EQ(scheme_, url.scheme());
170   CHECK_EQ(hostname_, url.host());
171   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
172                           base::Bind(&Delegate::SetResponse,
173                                      base::Unretained(delegate_), url, path,
174                                      true));
175 }
176 
GetHitCount()177 int URLRequestPrepackagedInterceptor::GetHitCount() {
178   return delegate_->GetHitCount();
179 }
180 
181 
182 URLLocalHostRequestPrepackagedInterceptor
URLLocalHostRequestPrepackagedInterceptor()183   ::URLLocalHostRequestPrepackagedInterceptor()
184     : URLRequestPrepackagedInterceptor("http", "localhost") {
185 }
186 
187 }  // namespace content
188