| OLD | NEW |
| (Empty) |
| 1 // Copyright 2013 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 "chrome/browser/component_updater/test/url_request_post_interceptor.h" | |
| 6 #include "base/file_util.h" | |
| 7 #include "base/memory/scoped_ptr.h" | |
| 8 #include "base/strings/stringprintf.h" | |
| 9 #include "content/public/test/test_browser_thread.h" | |
| 10 #include "net/base/upload_bytes_element_reader.h" | |
| 11 #include "net/url_request/url_request.h" | |
| 12 #include "net/url_request/url_request_filter.h" | |
| 13 #include "net/url_request/url_request_interceptor.h" | |
| 14 #include "net/url_request/url_request_simple_job.h" | |
| 15 #include "net/url_request/url_request_test_util.h" | |
| 16 | |
| 17 using content::BrowserThread; | |
| 18 | |
| 19 namespace component_updater { | |
| 20 | |
| 21 // Returns a canned response. | |
| 22 class URLRequestMockJob : public net::URLRequestSimpleJob { | |
| 23 public: | |
| 24 URLRequestMockJob(net::URLRequest* request, | |
| 25 net::NetworkDelegate* network_delegate, | |
| 26 const std::string& response) | |
| 27 : net::URLRequestSimpleJob(request, network_delegate), | |
| 28 response_(response) {} | |
| 29 | |
| 30 protected: | |
| 31 virtual int GetResponseCode() const OVERRIDE { return 200; } | |
| 32 | |
| 33 virtual int GetData(std::string* mime_type, | |
| 34 std::string* charset, | |
| 35 std::string* data, | |
| 36 const net::CompletionCallback& callback) const OVERRIDE { | |
| 37 mime_type->assign("text/plain"); | |
| 38 charset->assign("US-ASCII"); | |
| 39 data->assign(response_); | |
| 40 return net::OK; | |
| 41 } | |
| 42 | |
| 43 private: | |
| 44 virtual ~URLRequestMockJob() {} | |
| 45 | |
| 46 std::string response_; | |
| 47 DISALLOW_COPY_AND_ASSIGN(URLRequestMockJob); | |
| 48 }; | |
| 49 | |
| 50 URLRequestPostInterceptor::URLRequestPostInterceptor(const GURL& url) | |
| 51 : url_(url), hit_count_(0) { | |
| 52 } | |
| 53 | |
| 54 URLRequestPostInterceptor::~URLRequestPostInterceptor() { | |
| 55 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 56 ClearExpectations(); | |
| 57 } | |
| 58 | |
| 59 void URLRequestPostInterceptor::ClearExpectations() { | |
| 60 while (!expectations_.empty()) { | |
| 61 Expectation expectation(expectations_.front()); | |
| 62 delete expectation.first; | |
| 63 expectations_.pop(); | |
| 64 } | |
| 65 } | |
| 66 | |
| 67 GURL URLRequestPostInterceptor::GetUrl() const { | |
| 68 return url_; | |
| 69 } | |
| 70 | |
| 71 bool URLRequestPostInterceptor::ExpectRequest( | |
| 72 class RequestMatcher* request_matcher) { | |
| 73 expectations_.push(std::make_pair(request_matcher, "")); | |
| 74 return true; | |
| 75 } | |
| 76 | |
| 77 bool URLRequestPostInterceptor::ExpectRequest( | |
| 78 class RequestMatcher* request_matcher, | |
| 79 const base::FilePath& filepath) { | |
| 80 std::string response; | |
| 81 if (filepath.empty() || !base::ReadFileToString(filepath, &response)) | |
| 82 return false; | |
| 83 expectations_.push(std::make_pair(request_matcher, response)); | |
| 84 return true; | |
| 85 } | |
| 86 | |
| 87 int URLRequestPostInterceptor::GetHitCount() const { | |
| 88 base::AutoLock auto_lock(interceptor_lock_); | |
| 89 return hit_count_; | |
| 90 } | |
| 91 | |
| 92 int URLRequestPostInterceptor::GetCount() const { | |
| 93 base::AutoLock auto_lock(interceptor_lock_); | |
| 94 return static_cast<int>(requests_.size()); | |
| 95 } | |
| 96 | |
| 97 std::vector<std::string> URLRequestPostInterceptor::GetRequests() const { | |
| 98 base::AutoLock auto_lock(interceptor_lock_); | |
| 99 return requests_; | |
| 100 } | |
| 101 | |
| 102 std::string URLRequestPostInterceptor::GetRequestsAsString() const { | |
| 103 std::vector<std::string> requests(GetRequests()); | |
| 104 | |
| 105 std::string s = "Requests are:"; | |
| 106 | |
| 107 int i = 0; | |
| 108 for (std::vector<std::string>::const_iterator it = requests.begin(); | |
| 109 it != requests.end(); | |
| 110 ++it) { | |
| 111 s.append(base::StringPrintf("\n (%d): %s", ++i, it->c_str())); | |
| 112 } | |
| 113 | |
| 114 return s; | |
| 115 } | |
| 116 | |
| 117 void URLRequestPostInterceptor::Reset() { | |
| 118 base::AutoLock auto_lock(interceptor_lock_); | |
| 119 hit_count_ = 0; | |
| 120 requests_.clear(); | |
| 121 ClearExpectations(); | |
| 122 } | |
| 123 | |
| 124 class URLRequestPostInterceptor::Delegate : public net::URLRequestInterceptor { | |
| 125 public: | |
| 126 Delegate(const std::string& scheme, const std::string& hostname) | |
| 127 : scheme_(scheme), hostname_(hostname) {} | |
| 128 | |
| 129 void Register() { | |
| 130 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 131 net::URLRequestFilter::GetInstance()->AddHostnameInterceptor( | |
| 132 scheme_, hostname_, scoped_ptr<net::URLRequestInterceptor>(this)); | |
| 133 } | |
| 134 | |
| 135 void Unregister() { | |
| 136 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 137 for (InterceptorMap::iterator it = interceptors_.begin(); | |
| 138 it != interceptors_.end(); | |
| 139 ++it) | |
| 140 delete (*it).second; | |
| 141 net::URLRequestFilter::GetInstance()->RemoveHostnameHandler(scheme_, | |
| 142 hostname_); | |
| 143 } | |
| 144 | |
| 145 void OnCreateInterceptor(URLRequestPostInterceptor* interceptor) { | |
| 146 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 147 CHECK(interceptors_.find(interceptor->GetUrl()) == interceptors_.end()); | |
| 148 | |
| 149 interceptors_.insert(std::make_pair(interceptor->GetUrl(), interceptor)); | |
| 150 } | |
| 151 | |
| 152 private: | |
| 153 virtual ~Delegate() {} | |
| 154 | |
| 155 virtual net::URLRequestJob* MaybeInterceptRequest( | |
| 156 net::URLRequest* request, | |
| 157 net::NetworkDelegate* network_delegate) const OVERRIDE { | |
| 158 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 159 | |
| 160 // Only intercepts POST. | |
| 161 if (!request->has_upload()) | |
| 162 return NULL; | |
| 163 | |
| 164 GURL url = request->url(); | |
| 165 if (url.has_query()) { | |
| 166 GURL::Replacements replacements; | |
| 167 replacements.ClearQuery(); | |
| 168 url = url.ReplaceComponents(replacements); | |
| 169 } | |
| 170 | |
| 171 InterceptorMap::const_iterator it(interceptors_.find(url)); | |
| 172 if (it == interceptors_.end()) | |
| 173 return NULL; | |
| 174 | |
| 175 // There is an interceptor hooked up for this url. Read the request body, | |
| 176 // check the existing expectations, and handle the matching case by | |
| 177 // popping the expectation off the queue, counting the match, and | |
| 178 // returning a mock object to serve the canned response. | |
| 179 URLRequestPostInterceptor* interceptor(it->second); | |
| 180 | |
| 181 const net::UploadDataStream* stream = request->get_upload(); | |
| 182 const net::UploadBytesElementReader* reader = | |
| 183 stream->element_readers()[0]->AsBytesReader(); | |
| 184 const int size = reader->length(); | |
| 185 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(size)); | |
| 186 const std::string request_body(reader->bytes()); | |
| 187 | |
| 188 { | |
| 189 base::AutoLock auto_lock(interceptor->interceptor_lock_); | |
| 190 interceptor->requests_.push_back(request_body); | |
| 191 if (interceptor->expectations_.empty()) | |
| 192 return NULL; | |
| 193 const URLRequestPostInterceptor::Expectation& expectation( | |
| 194 interceptor->expectations_.front()); | |
| 195 if (expectation.first->Match(request_body)) { | |
| 196 const std::string response(expectation.second); | |
| 197 delete expectation.first; | |
| 198 interceptor->expectations_.pop(); | |
| 199 ++interceptor->hit_count_; | |
| 200 | |
| 201 return new URLRequestMockJob(request, network_delegate, response); | |
| 202 } | |
| 203 } | |
| 204 | |
| 205 return NULL; | |
| 206 } | |
| 207 | |
| 208 typedef std::map<GURL, URLRequestPostInterceptor*> InterceptorMap; | |
| 209 InterceptorMap interceptors_; | |
| 210 | |
| 211 const std::string scheme_; | |
| 212 const std::string hostname_; | |
| 213 | |
| 214 DISALLOW_COPY_AND_ASSIGN(Delegate); | |
| 215 }; | |
| 216 | |
| 217 URLRequestPostInterceptorFactory::URLRequestPostInterceptorFactory( | |
| 218 const std::string& scheme, | |
| 219 const std::string& hostname) | |
| 220 : scheme_(scheme), | |
| 221 hostname_(hostname), | |
| 222 delegate_(new URLRequestPostInterceptor::Delegate(scheme, hostname)) { | |
| 223 BrowserThread::PostTask( | |
| 224 BrowserThread::IO, | |
| 225 FROM_HERE, | |
| 226 base::Bind(&URLRequestPostInterceptor::Delegate::Register, | |
| 227 base::Unretained(delegate_))); | |
| 228 } | |
| 229 | |
| 230 URLRequestPostInterceptorFactory::~URLRequestPostInterceptorFactory() { | |
| 231 BrowserThread::PostTask( | |
| 232 BrowserThread::IO, | |
| 233 FROM_HERE, | |
| 234 base::Bind(&URLRequestPostInterceptor::Delegate::Unregister, | |
| 235 base::Unretained(delegate_))); | |
| 236 } | |
| 237 | |
| 238 URLRequestPostInterceptor* URLRequestPostInterceptorFactory::CreateInterceptor( | |
| 239 const base::FilePath& filepath) { | |
| 240 const GURL base_url( | |
| 241 base::StringPrintf("%s://%s", scheme_.c_str(), hostname_.c_str())); | |
| 242 GURL absolute_url(base_url.Resolve(filepath.MaybeAsASCII())); | |
| 243 URLRequestPostInterceptor* interceptor( | |
| 244 new URLRequestPostInterceptor(absolute_url)); | |
| 245 bool res = BrowserThread::PostTask( | |
| 246 BrowserThread::IO, | |
| 247 FROM_HERE, | |
| 248 base::Bind(&URLRequestPostInterceptor::Delegate::OnCreateInterceptor, | |
| 249 base::Unretained(delegate_), | |
| 250 base::Unretained(interceptor))); | |
| 251 if (!res) { | |
| 252 delete interceptor; | |
| 253 return NULL; | |
| 254 } | |
| 255 | |
| 256 return interceptor; | |
| 257 } | |
| 258 | |
| 259 } // namespace component_updater | |
| OLD | NEW |