Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1597)

Side by Side Diff: chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc

Issue 657373004: Standardize usage of virtual/override/final in chrome/browser/safe_browsing/ (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 // 4 //
5 // This test creates a fake safebrowsing service, where we can inject 5 // This test creates a fake safebrowsing service, where we can inject
6 // malware and phishing urls. It then uses a real browser to go to 6 // malware and phishing urls. It then uses a real browser to go to
7 // these urls, and sends "goback" or "proceed" commands and verifies 7 // these urls, and sends "goback" or "proceed" commands and verifies
8 // they work. 8 // they work.
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
54 class FakeSafeBrowsingDatabaseManager : public SafeBrowsingDatabaseManager { 54 class FakeSafeBrowsingDatabaseManager : public SafeBrowsingDatabaseManager {
55 public: 55 public:
56 explicit FakeSafeBrowsingDatabaseManager(SafeBrowsingService* service) 56 explicit FakeSafeBrowsingDatabaseManager(SafeBrowsingService* service)
57 : SafeBrowsingDatabaseManager(service) { } 57 : SafeBrowsingDatabaseManager(service) { }
58 58
59 // Called on the IO thread to check if the given url is safe or not. If we 59 // Called on the IO thread to check if the given url is safe or not. If we
60 // can synchronously determine that the url is safe, CheckUrl returns true. 60 // can synchronously determine that the url is safe, CheckUrl returns true.
61 // Otherwise it returns false, and "client" is called asynchronously with the 61 // Otherwise it returns false, and "client" is called asynchronously with the
62 // result when it is ready. 62 // result when it is ready.
63 // Overrides SafeBrowsingDatabaseManager::CheckBrowseUrl. 63 // Overrides SafeBrowsingDatabaseManager::CheckBrowseUrl.
64 virtual bool CheckBrowseUrl(const GURL& gurl, Client* client) override { 64 bool CheckBrowseUrl(const GURL& gurl, Client* client) override {
65 if (badurls[gurl.spec()] == SB_THREAT_TYPE_SAFE) 65 if (badurls[gurl.spec()] == SB_THREAT_TYPE_SAFE)
66 return true; 66 return true;
67 67
68 BrowserThread::PostTask( 68 BrowserThread::PostTask(
69 BrowserThread::IO, FROM_HERE, 69 BrowserThread::IO, FROM_HERE,
70 base::Bind(&FakeSafeBrowsingDatabaseManager::OnCheckBrowseURLDone, 70 base::Bind(&FakeSafeBrowsingDatabaseManager::OnCheckBrowseURLDone,
71 this, gurl, client)); 71 this, gurl, client));
72 return false; 72 return false;
73 } 73 }
74 74
75 void OnCheckBrowseURLDone(const GURL& gurl, Client* client) { 75 void OnCheckBrowseURLDone(const GURL& gurl, Client* client) {
76 std::vector<SBThreatType> expected_threats; 76 std::vector<SBThreatType> expected_threats;
77 expected_threats.push_back(SB_THREAT_TYPE_URL_MALWARE); 77 expected_threats.push_back(SB_THREAT_TYPE_URL_MALWARE);
78 expected_threats.push_back(SB_THREAT_TYPE_URL_PHISHING); 78 expected_threats.push_back(SB_THREAT_TYPE_URL_PHISHING);
79 SafeBrowsingDatabaseManager::SafeBrowsingCheck sb_check( 79 SafeBrowsingDatabaseManager::SafeBrowsingCheck sb_check(
80 std::vector<GURL>(1, gurl), 80 std::vector<GURL>(1, gurl),
81 std::vector<SBFullHash>(), 81 std::vector<SBFullHash>(),
82 client, 82 client,
83 safe_browsing_util::MALWARE, 83 safe_browsing_util::MALWARE,
84 expected_threats); 84 expected_threats);
85 sb_check.url_results[0] = badurls[gurl.spec()]; 85 sb_check.url_results[0] = badurls[gurl.spec()];
86 client->OnSafeBrowsingResult(sb_check); 86 client->OnSafeBrowsingResult(sb_check);
87 } 87 }
88 88
89 void SetURLThreatType(const GURL& url, SBThreatType threat_type) { 89 void SetURLThreatType(const GURL& url, SBThreatType threat_type) {
90 badurls[url.spec()] = threat_type; 90 badurls[url.spec()] = threat_type;
91 } 91 }
92 92
93 private: 93 private:
94 virtual ~FakeSafeBrowsingDatabaseManager() {} 94 ~FakeSafeBrowsingDatabaseManager() override {}
95 95
96 base::hash_map<std::string, SBThreatType> badurls; 96 base::hash_map<std::string, SBThreatType> badurls;
97 DISALLOW_COPY_AND_ASSIGN(FakeSafeBrowsingDatabaseManager); 97 DISALLOW_COPY_AND_ASSIGN(FakeSafeBrowsingDatabaseManager);
98 }; 98 };
99 99
100 // A SafeBrowingUIManager class that allows intercepting malware details. 100 // A SafeBrowingUIManager class that allows intercepting malware details.
101 class FakeSafeBrowsingUIManager : public SafeBrowsingUIManager { 101 class FakeSafeBrowsingUIManager : public SafeBrowsingUIManager {
102 public: 102 public:
103 explicit FakeSafeBrowsingUIManager(SafeBrowsingService* service) : 103 explicit FakeSafeBrowsingUIManager(SafeBrowsingService* service) :
104 SafeBrowsingUIManager(service) { } 104 SafeBrowsingUIManager(service) { }
105 105
106 // Overrides SafeBrowsingUIManager 106 // Overrides SafeBrowsingUIManager
107 virtual void SendSerializedMalwareDetails( 107 void SendSerializedMalwareDetails(const std::string& serialized) override {
108 const std::string& serialized) override {
109 // Notify the UI thread that we got a report. 108 // Notify the UI thread that we got a report.
110 BrowserThread::PostTask( 109 BrowserThread::PostTask(
111 BrowserThread::UI, 110 BrowserThread::UI,
112 FROM_HERE, 111 FROM_HERE,
113 base::Bind(&FakeSafeBrowsingUIManager::OnMalwareDetailsDone, 112 base::Bind(&FakeSafeBrowsingUIManager::OnMalwareDetailsDone,
114 this, 113 this,
115 serialized)); 114 serialized));
116 } 115 }
117 116
118 void OnMalwareDetailsDone(const std::string& serialized) { 117 void OnMalwareDetailsDone(const std::string& serialized) {
(...skipping 12 matching lines...) Expand all
131 EXPECT_TRUE(malware_details_done_callback_.is_null()); 130 EXPECT_TRUE(malware_details_done_callback_.is_null());
132 malware_details_done_callback_ = callback; 131 malware_details_done_callback_ = callback;
133 } 132 }
134 133
135 std::string GetReport() { 134 std::string GetReport() {
136 EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI)); 135 EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI));
137 return report_; 136 return report_;
138 } 137 }
139 138
140 protected: 139 protected:
141 virtual ~FakeSafeBrowsingUIManager() { } 140 ~FakeSafeBrowsingUIManager() override {}
142 141
143 private: 142 private:
144 std::string report_; 143 std::string report_;
145 base::Closure malware_details_done_callback_; 144 base::Closure malware_details_done_callback_;
146 145
147 DISALLOW_COPY_AND_ASSIGN(FakeSafeBrowsingUIManager); 146 DISALLOW_COPY_AND_ASSIGN(FakeSafeBrowsingUIManager);
148 }; 147 };
149 148
150 class FakeSafeBrowsingService : public SafeBrowsingService { 149 class FakeSafeBrowsingService : public SafeBrowsingService {
151 public: 150 public:
152 FakeSafeBrowsingService() 151 FakeSafeBrowsingService()
153 : fake_database_manager_(), 152 : fake_database_manager_(),
154 fake_ui_manager_() { } 153 fake_ui_manager_() { }
155 154
156 // Returned pointer has the same lifespan as the database_manager_ refcounted 155 // Returned pointer has the same lifespan as the database_manager_ refcounted
157 // object. 156 // object.
158 FakeSafeBrowsingDatabaseManager* fake_database_manager() { 157 FakeSafeBrowsingDatabaseManager* fake_database_manager() {
159 return fake_database_manager_; 158 return fake_database_manager_;
160 } 159 }
161 // Returned pointer has the same lifespan as the ui_manager_ refcounted 160 // Returned pointer has the same lifespan as the ui_manager_ refcounted
162 // object. 161 // object.
163 FakeSafeBrowsingUIManager* fake_ui_manager() { 162 FakeSafeBrowsingUIManager* fake_ui_manager() {
164 return fake_ui_manager_; 163 return fake_ui_manager_;
165 } 164 }
166 165
167 protected: 166 protected:
168 virtual ~FakeSafeBrowsingService() { } 167 ~FakeSafeBrowsingService() override {}
169 168
170 virtual SafeBrowsingDatabaseManager* CreateDatabaseManager() override { 169 SafeBrowsingDatabaseManager* CreateDatabaseManager() override {
171 fake_database_manager_ = new FakeSafeBrowsingDatabaseManager(this); 170 fake_database_manager_ = new FakeSafeBrowsingDatabaseManager(this);
172 return fake_database_manager_; 171 return fake_database_manager_;
173 } 172 }
174 173
175 virtual SafeBrowsingUIManager* CreateUIManager() override { 174 SafeBrowsingUIManager* CreateUIManager() override {
176 fake_ui_manager_ = new FakeSafeBrowsingUIManager(this); 175 fake_ui_manager_ = new FakeSafeBrowsingUIManager(this);
177 return fake_ui_manager_; 176 return fake_ui_manager_;
178 } 177 }
179 178
180 private: 179 private:
181 FakeSafeBrowsingDatabaseManager* fake_database_manager_; 180 FakeSafeBrowsingDatabaseManager* fake_database_manager_;
182 FakeSafeBrowsingUIManager* fake_ui_manager_; 181 FakeSafeBrowsingUIManager* fake_ui_manager_;
183 182
184 DISALLOW_COPY_AND_ASSIGN(FakeSafeBrowsingService); 183 DISALLOW_COPY_AND_ASSIGN(FakeSafeBrowsingService);
185 }; 184 };
186 185
187 // Factory that creates FakeSafeBrowsingService instances. 186 // Factory that creates FakeSafeBrowsingService instances.
188 class TestSafeBrowsingServiceFactory : public SafeBrowsingServiceFactory { 187 class TestSafeBrowsingServiceFactory : public SafeBrowsingServiceFactory {
189 public: 188 public:
190 TestSafeBrowsingServiceFactory() : 189 TestSafeBrowsingServiceFactory() :
191 most_recent_service_(NULL) { } 190 most_recent_service_(NULL) { }
192 virtual ~TestSafeBrowsingServiceFactory() { } 191 ~TestSafeBrowsingServiceFactory() override {}
193 192
194 virtual SafeBrowsingService* CreateSafeBrowsingService() override { 193 SafeBrowsingService* CreateSafeBrowsingService() override {
195 most_recent_service_ = new FakeSafeBrowsingService(); 194 most_recent_service_ = new FakeSafeBrowsingService();
196 return most_recent_service_; 195 return most_recent_service_;
197 } 196 }
198 197
199 FakeSafeBrowsingService* most_recent_service() const { 198 FakeSafeBrowsingService* most_recent_service() const {
200 return most_recent_service_; 199 return most_recent_service_;
201 } 200 }
202 201
203 private: 202 private:
204 FakeSafeBrowsingService* most_recent_service_; 203 FakeSafeBrowsingService* most_recent_service_;
205 }; 204 };
206 205
207 // A MalwareDetails class lets us intercept calls from the renderer. 206 // A MalwareDetails class lets us intercept calls from the renderer.
208 class FakeMalwareDetails : public MalwareDetails { 207 class FakeMalwareDetails : public MalwareDetails {
209 public: 208 public:
210 FakeMalwareDetails( 209 FakeMalwareDetails(
211 SafeBrowsingUIManager* delegate, 210 SafeBrowsingUIManager* delegate,
212 WebContents* web_contents, 211 WebContents* web_contents,
213 const SafeBrowsingUIManager::UnsafeResource& unsafe_resource) 212 const SafeBrowsingUIManager::UnsafeResource& unsafe_resource)
214 : MalwareDetails(delegate, web_contents, unsafe_resource), 213 : MalwareDetails(delegate, web_contents, unsafe_resource),
215 got_dom_(false), 214 got_dom_(false),
216 waiting_(false) { } 215 waiting_(false) { }
217 216
218 virtual void AddDOMDetails( 217 void AddDOMDetails(
219 const std::vector<SafeBrowsingHostMsg_MalwareDOMDetails_Node>& params) 218 const std::vector<SafeBrowsingHostMsg_MalwareDOMDetails_Node>& params)
220 override { 219 override {
221 EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO)); 220 EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
222 MalwareDetails::AddDOMDetails(params); 221 MalwareDetails::AddDOMDetails(params);
223 222
224 // Notify the UI thread that we got the dom details. 223 // Notify the UI thread that we got the dom details.
225 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 224 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
226 base::Bind(&FakeMalwareDetails::OnDOMDetailsDone, 225 base::Bind(&FakeMalwareDetails::OnDOMDetailsDone,
227 this)); 226 this));
228 } 227 }
229 228
230 void WaitForDOM() { 229 void WaitForDOM() {
231 if (got_dom_) { 230 if (got_dom_) {
232 return; 231 return;
233 } 232 }
234 // This condition might not trigger normally, but if you add a 233 // This condition might not trigger normally, but if you add a
235 // sleep(1) in malware_dom_details it triggers :). 234 // sleep(1) in malware_dom_details it triggers :).
236 waiting_ = true; 235 waiting_ = true;
237 content::RunMessageLoop(); 236 content::RunMessageLoop();
238 EXPECT_TRUE(got_dom_); 237 EXPECT_TRUE(got_dom_);
239 } 238 }
240 239
241 private: 240 private:
242 virtual ~FakeMalwareDetails() {} 241 ~FakeMalwareDetails() override {}
243 242
244 void OnDOMDetailsDone() { 243 void OnDOMDetailsDone() {
245 got_dom_ = true; 244 got_dom_ = true;
246 if (waiting_) { 245 if (waiting_) {
247 base::MessageLoopForUI::current()->Quit(); 246 base::MessageLoopForUI::current()->Quit();
248 } 247 }
249 } 248 }
250 249
251 // Some logic to figure out if we should wait for the dom details or not. 250 // Some logic to figure out if we should wait for the dom details or not.
252 // These variables should only be accessed in the UI thread. 251 // These variables should only be accessed in the UI thread.
253 bool got_dom_; 252 bool got_dom_;
254 bool waiting_; 253 bool waiting_;
255 }; 254 };
256 255
257 class TestMalwareDetailsFactory : public MalwareDetailsFactory { 256 class TestMalwareDetailsFactory : public MalwareDetailsFactory {
258 public: 257 public:
259 TestMalwareDetailsFactory() : details_() { } 258 TestMalwareDetailsFactory() : details_() { }
260 virtual ~TestMalwareDetailsFactory() { } 259 ~TestMalwareDetailsFactory() override {}
261 260
262 virtual MalwareDetails* CreateMalwareDetails( 261 MalwareDetails* CreateMalwareDetails(
263 SafeBrowsingUIManager* delegate, 262 SafeBrowsingUIManager* delegate,
264 WebContents* web_contents, 263 WebContents* web_contents,
265 const SafeBrowsingUIManager::UnsafeResource& unsafe_resource) override { 264 const SafeBrowsingUIManager::UnsafeResource& unsafe_resource) override {
266 details_ = new FakeMalwareDetails(delegate, web_contents, 265 details_ = new FakeMalwareDetails(delegate, web_contents,
267 unsafe_resource); 266 unsafe_resource);
268 return details_; 267 return details_;
269 } 268 }
270 269
271 FakeMalwareDetails* get_details() { 270 FakeMalwareDetails* get_details() {
272 return details_; 271 return details_;
273 } 272 }
274 273
275 private: 274 private:
276 FakeMalwareDetails* details_; 275 FakeMalwareDetails* details_;
277 }; 276 };
278 277
279 // A SafeBrowingBlockingPage class that lets us wait until it's hidden. 278 // A SafeBrowingBlockingPage class that lets us wait until it's hidden.
280 class TestSafeBrowsingBlockingPage : public SafeBrowsingBlockingPage { 279 class TestSafeBrowsingBlockingPage : public SafeBrowsingBlockingPage {
281 public: 280 public:
282 TestSafeBrowsingBlockingPage(SafeBrowsingUIManager* manager, 281 TestSafeBrowsingBlockingPage(SafeBrowsingUIManager* manager,
283 WebContents* web_contents, 282 WebContents* web_contents,
284 const UnsafeResourceList& unsafe_resources) 283 const UnsafeResourceList& unsafe_resources)
285 : SafeBrowsingBlockingPage(manager, web_contents, unsafe_resources), 284 : SafeBrowsingBlockingPage(manager, web_contents, unsafe_resources),
286 wait_for_delete_(false) { 285 wait_for_delete_(false) {
287 // Don't wait the whole 3 seconds for the browser test. 286 // Don't wait the whole 3 seconds for the browser test.
288 malware_details_proceed_delay_ms_ = 100; 287 malware_details_proceed_delay_ms_ = 100;
289 } 288 }
290 289
291 virtual ~TestSafeBrowsingBlockingPage() { 290 ~TestSafeBrowsingBlockingPage() override {
292 if (!wait_for_delete_) 291 if (!wait_for_delete_)
293 return; 292 return;
294 293
295 // Notify that we are gone 294 // Notify that we are gone
296 base::MessageLoopForUI::current()->Quit(); 295 base::MessageLoopForUI::current()->Quit();
297 wait_for_delete_ = false; 296 wait_for_delete_ = false;
298 } 297 }
299 298
300 void WaitForDelete() { 299 void WaitForDelete() {
301 wait_for_delete_ = true; 300 wait_for_delete_ = true;
302 content::RunMessageLoop(); 301 content::RunMessageLoop();
303 } 302 }
304 303
305 // InterstitialPageDelegate methods: 304 // InterstitialPageDelegate methods:
306 virtual void CommandReceived(const std::string& command) override { 305 void CommandReceived(const std::string& command) override {
307 SafeBrowsingBlockingPage::CommandReceived(command); 306 SafeBrowsingBlockingPage::CommandReceived(command);
308 } 307 }
309 virtual void OnProceed() override { 308 void OnProceed() override { SafeBrowsingBlockingPage::OnProceed(); }
310 SafeBrowsingBlockingPage::OnProceed(); 309 void OnDontProceed() override { SafeBrowsingBlockingPage::OnDontProceed(); }
311 }
312 virtual void OnDontProceed() override {
313 SafeBrowsingBlockingPage::OnDontProceed();
314 }
315 310
316 private: 311 private:
317 bool wait_for_delete_; 312 bool wait_for_delete_;
318 }; 313 };
319 314
320 class TestSafeBrowsingBlockingPageFactory 315 class TestSafeBrowsingBlockingPageFactory
321 : public SafeBrowsingBlockingPageFactory { 316 : public SafeBrowsingBlockingPageFactory {
322 public: 317 public:
323 TestSafeBrowsingBlockingPageFactory() { } 318 TestSafeBrowsingBlockingPageFactory() { }
324 virtual ~TestSafeBrowsingBlockingPageFactory() { } 319 ~TestSafeBrowsingBlockingPageFactory() override {}
325 320
326 virtual SafeBrowsingBlockingPage* CreateSafeBrowsingPage( 321 SafeBrowsingBlockingPage* CreateSafeBrowsingPage(
327 SafeBrowsingUIManager* delegate, 322 SafeBrowsingUIManager* delegate,
328 WebContents* web_contents, 323 WebContents* web_contents,
329 const SafeBrowsingBlockingPage::UnsafeResourceList& unsafe_resources) 324 const SafeBrowsingBlockingPage::UnsafeResourceList& unsafe_resources)
330 override { 325 override {
331 return new TestSafeBrowsingBlockingPage(delegate, web_contents, 326 return new TestSafeBrowsingBlockingPage(delegate, web_contents,
332 unsafe_resources); 327 unsafe_resources);
333 } 328 }
334 }; 329 };
335 330
336 } // namespace 331 } // namespace
337 332
338 // Tests the safe browsing blocking page in a browser. 333 // Tests the safe browsing blocking page in a browser.
339 class SafeBrowsingBlockingPageBrowserTest 334 class SafeBrowsingBlockingPageBrowserTest
340 : public InProcessBrowserTest, 335 : public InProcessBrowserTest,
(...skipping 15 matching lines...) Expand all
356 InProcessBrowserTest::SetUp(); 351 InProcessBrowserTest::SetUp();
357 } 352 }
358 353
359 virtual void TearDown() override { 354 virtual void TearDown() override {
360 InProcessBrowserTest::TearDown(); 355 InProcessBrowserTest::TearDown();
361 SafeBrowsingBlockingPage::RegisterFactory(NULL); 356 SafeBrowsingBlockingPage::RegisterFactory(NULL);
362 SafeBrowsingService::RegisterFactory(NULL); 357 SafeBrowsingService::RegisterFactory(NULL);
363 MalwareDetails::RegisterFactory(NULL); 358 MalwareDetails::RegisterFactory(NULL);
364 } 359 }
365 360
366 virtual void SetUpInProcessBrowserTestFixture() override { 361 void SetUpInProcessBrowserTestFixture() override {
367 ASSERT_TRUE(test_server()->Start()); 362 ASSERT_TRUE(test_server()->Start());
368 } 363 }
369 364
370 void SetURLThreatType(const GURL& url, SBThreatType threat_type) { 365 void SetURLThreatType(const GURL& url, SBThreatType threat_type) {
371 FakeSafeBrowsingService* service = 366 FakeSafeBrowsingService* service =
372 static_cast<FakeSafeBrowsingService*>( 367 static_cast<FakeSafeBrowsingService*>(
373 g_browser_process->safe_browsing_service()); 368 g_browser_process->safe_browsing_service());
374 369
375 ASSERT_TRUE(service); 370 ASSERT_TRUE(service);
376 service->fake_database_manager()->SetURLThreatType(url, threat_type); 371 service->fake_database_manager()->SetURLThreatType(url, threat_type);
(...skipping 465 matching lines...) Expand 10 before | Expand all | Expand 10 after
842 IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageBrowserTest, PhishingLearnMore) { 837 IN_PROC_BROWSER_TEST_F(SafeBrowsingBlockingPageBrowserTest, PhishingLearnMore) {
843 SetupWarningAndNavigate(SB_THREAT_TYPE_URL_PHISHING); 838 SetupWarningAndNavigate(SB_THREAT_TYPE_URL_PHISHING);
844 EXPECT_TRUE(ClickAndWaitForDetach("help-link")); 839 EXPECT_TRUE(ClickAndWaitForDetach("help-link"));
845 AssertNoInterstitial(false); // Assert the interstitial is gone 840 AssertNoInterstitial(false); // Assert the interstitial is gone
846 841
847 // We are in the help page. 842 // We are in the help page.
848 EXPECT_EQ( 843 EXPECT_EQ(
849 "/transparencyreport/safebrowsing/", 844 "/transparencyreport/safebrowsing/",
850 browser()->tab_strip_model()->GetActiveWebContents()->GetURL().path()); 845 browser()->tab_strip_model()->GetActiveWebContents()->GetURL().path());
851 } 846 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698