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