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