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/update_client/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/update_client/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 update_client { |
| 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(); ++it) { |
| 127 s.append(base::StringPrintf("\n (%d): %s", ++i, it->c_str())); |
| 128 } |
| 129 |
| 130 return s; |
| 131 } |
| 132 |
| 133 void URLRequestPostInterceptor::Reset() { |
| 134 base::AutoLock auto_lock(interceptor_lock_); |
| 135 hit_count_ = 0; |
| 136 requests_.clear(); |
| 137 ClearExpectations(); |
| 138 } |
| 139 |
| 140 class URLRequestPostInterceptor::Delegate : public net::URLRequestInterceptor { |
| 141 public: |
| 142 Delegate(const std::string& scheme, |
| 143 const std::string& hostname, |
| 144 const scoped_refptr<base::SequencedTaskRunner>& io_task_runner) |
| 145 : scheme_(scheme), hostname_(hostname), io_task_runner_(io_task_runner) {} |
| 146 |
| 147 void Register() { |
| 148 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); |
| 149 net::URLRequestFilter::GetInstance()->AddHostnameInterceptor( |
| 150 scheme_, hostname_, scoped_ptr<net::URLRequestInterceptor>(this)); |
| 151 } |
| 152 |
| 153 void Unregister() { |
| 154 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); |
| 155 for (InterceptorMap::iterator it = interceptors_.begin(); |
| 156 it != interceptors_.end(); ++it) |
| 157 delete (*it).second; |
| 158 net::URLRequestFilter::GetInstance()->RemoveHostnameHandler(scheme_, |
| 159 hostname_); |
| 160 } |
| 161 |
| 162 void OnCreateInterceptor(URLRequestPostInterceptor* interceptor) { |
| 163 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); |
| 164 DCHECK(interceptors_.find(interceptor->GetUrl()) == interceptors_.end()); |
| 165 |
| 166 interceptors_.insert(std::make_pair(interceptor->GetUrl(), interceptor)); |
| 167 } |
| 168 |
| 169 private: |
| 170 ~Delegate() override {} |
| 171 |
| 172 net::URLRequestJob* MaybeInterceptRequest( |
| 173 net::URLRequest* request, |
| 174 net::NetworkDelegate* network_delegate) const override { |
| 175 DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); |
| 176 |
| 177 // Only intercepts POST. |
| 178 if (!request->has_upload()) |
| 179 return NULL; |
| 180 |
| 181 GURL url = request->url(); |
| 182 if (url.has_query()) { |
| 183 GURL::Replacements replacements; |
| 184 replacements.ClearQuery(); |
| 185 url = url.ReplaceComponents(replacements); |
| 186 } |
| 187 |
| 188 InterceptorMap::const_iterator it(interceptors_.find(url)); |
| 189 if (it == interceptors_.end()) |
| 190 return NULL; |
| 191 |
| 192 // There is an interceptor hooked up for this url. Read the request body, |
| 193 // check the existing expectations, and handle the matching case by |
| 194 // popping the expectation off the queue, counting the match, and |
| 195 // returning a mock object to serve the canned response. |
| 196 URLRequestPostInterceptor* interceptor(it->second); |
| 197 |
| 198 const net::UploadDataStream* stream = request->get_upload(); |
| 199 const net::UploadBytesElementReader* reader = |
| 200 (*stream->GetElementReaders())[0]->AsBytesReader(); |
| 201 const int size = reader->length(); |
| 202 scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(size)); |
| 203 const std::string request_body(reader->bytes()); |
| 204 |
| 205 { |
| 206 base::AutoLock auto_lock(interceptor->interceptor_lock_); |
| 207 interceptor->requests_.push_back(request_body); |
| 208 if (interceptor->expectations_.empty()) |
| 209 return NULL; |
| 210 const URLRequestPostInterceptor::Expectation& expectation( |
| 211 interceptor->expectations_.front()); |
| 212 if (expectation.first->Match(request_body)) { |
| 213 const int response_code(expectation.second.response_code); |
| 214 const std::string response_body(expectation.second.response_body); |
| 215 delete expectation.first; |
| 216 interceptor->expectations_.pop(); |
| 217 ++interceptor->hit_count_; |
| 218 |
| 219 return new URLRequestMockJob(request, network_delegate, response_code, |
| 220 response_body); |
| 221 } |
| 222 } |
| 223 |
| 224 return NULL; |
| 225 } |
| 226 |
| 227 typedef std::map<GURL, URLRequestPostInterceptor*> InterceptorMap; |
| 228 InterceptorMap interceptors_; |
| 229 |
| 230 const std::string scheme_; |
| 231 const std::string hostname_; |
| 232 scoped_refptr<base::SequencedTaskRunner> io_task_runner_; |
| 233 |
| 234 DISALLOW_COPY_AND_ASSIGN(Delegate); |
| 235 }; |
| 236 |
| 237 URLRequestPostInterceptorFactory::URLRequestPostInterceptorFactory( |
| 238 const std::string& scheme, |
| 239 const std::string& hostname, |
| 240 const scoped_refptr<base::SequencedTaskRunner>& io_task_runner) |
| 241 : scheme_(scheme), |
| 242 hostname_(hostname), |
| 243 io_task_runner_(io_task_runner), |
| 244 delegate_(new URLRequestPostInterceptor::Delegate(scheme, |
| 245 hostname, |
| 246 io_task_runner)) { |
| 247 io_task_runner_->PostTask( |
| 248 FROM_HERE, base::Bind(&URLRequestPostInterceptor::Delegate::Register, |
| 249 base::Unretained(delegate_))); |
| 250 } |
| 251 |
| 252 URLRequestPostInterceptorFactory::~URLRequestPostInterceptorFactory() { |
| 253 io_task_runner_->PostTask( |
| 254 FROM_HERE, base::Bind(&URLRequestPostInterceptor::Delegate::Unregister, |
| 255 base::Unretained(delegate_))); |
| 256 } |
| 257 |
| 258 URLRequestPostInterceptor* URLRequestPostInterceptorFactory::CreateInterceptor( |
| 259 const base::FilePath& filepath) { |
| 260 const GURL base_url( |
| 261 base::StringPrintf("%s://%s", scheme_.c_str(), hostname_.c_str())); |
| 262 GURL absolute_url(base_url.Resolve(filepath.MaybeAsASCII())); |
| 263 URLRequestPostInterceptor* interceptor( |
| 264 new URLRequestPostInterceptor(absolute_url, io_task_runner_)); |
| 265 bool res = io_task_runner_->PostTask( |
| 266 FROM_HERE, |
| 267 base::Bind(&URLRequestPostInterceptor::Delegate::OnCreateInterceptor, |
| 268 base::Unretained(delegate_), base::Unretained(interceptor))); |
| 269 if (!res) { |
| 270 delete interceptor; |
| 271 return NULL; |
| 272 } |
| 273 |
| 274 return interceptor; |
| 275 } |
| 276 |
| 277 bool PartialMatch::Match(const std::string& actual) const { |
| 278 return actual.find(expected_) != std::string::npos; |
| 279 } |
| 280 |
| 281 InterceptorFactory::InterceptorFactory( |
| 282 const scoped_refptr<base::SequencedTaskRunner>& io_task_runner) |
| 283 : URLRequestPostInterceptorFactory(POST_INTERCEPT_SCHEME, |
| 284 POST_INTERCEPT_HOSTNAME, |
| 285 io_task_runner) { |
| 286 } |
| 287 |
| 288 InterceptorFactory::~InterceptorFactory() { |
| 289 } |
| 290 |
| 291 URLRequestPostInterceptor* InterceptorFactory::CreateInterceptor() { |
| 292 return CreateInterceptorForPath(POST_INTERCEPT_PATH); |
| 293 } |
| 294 |
| 295 URLRequestPostInterceptor* InterceptorFactory::CreateInterceptorForPath( |
| 296 const char* url_path) { |
| 297 return URLRequestPostInterceptorFactory::CreateInterceptor( |
| 298 base::FilePath::FromUTF8Unsafe(url_path)); |
| 299 } |
| 300 |
| 301 } // namespace update_client |
OLD | NEW |