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 "base/files/file_util.h" | |
6 #include "base/memory/scoped_ptr.h" | |
7 #include "base/strings/stringprintf.h" | |
8 #include "chrome/browser/component_updater/test/url_request_post_interceptor.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 |