OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 #include "chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate. h" | 5 #include "chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate. h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include <memory> | 9 #include <memory> |
10 #include <utility> | 10 #include <utility> |
11 | 11 |
12 #include "base/command_line.h" | 12 #include "base/command_line.h" |
13 #include "base/macros.h" | 13 #include "base/macros.h" |
14 #include "base/strings/string_util.h" | 14 #include "base/strings/string_util.h" |
15 #include "base/test/scoped_command_line.h" | |
15 #include "chrome/browser/browser_process.h" | 16 #include "chrome/browser/browser_process.h" |
16 #include "chrome/browser/policy/cloud/policy_header_service_factory.h" | 17 #include "chrome/browser/policy/cloud/policy_header_service_factory.h" |
17 #include "chrome/browser/profiles/profile.h" | 18 #include "chrome/browser/profiles/profile.h" |
18 #include "chrome/browser/renderer_host/chrome_navigation_data.h" | 19 #include "chrome/browser/renderer_host/chrome_navigation_data.h" |
19 #include "chrome/browser/ui/browser.h" | 20 #include "chrome/browser/ui/browser.h" |
20 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 21 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
21 #include "chrome/test/base/in_process_browser_test.h" | 22 #include "chrome/test/base/in_process_browser_test.h" |
22 #include "chrome/test/base/ui_test_utils.h" | 23 #include "chrome/test/base/ui_test_utils.h" |
23 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_data .h" | 24 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_data .h" |
24 #include "components/policy/core/common/cloud/cloud_policy_constants.h" | 25 #include "components/policy/core/common/cloud/cloud_policy_constants.h" |
25 #include "components/policy/core/common/cloud/policy_header_io_helper.h" | 26 #include "components/policy/core/common/cloud/policy_header_io_helper.h" |
26 #include "components/policy/core/common/cloud/policy_header_service.h" | 27 #include "components/policy/core/common/cloud/policy_header_service.h" |
27 #include "components/policy/core/common/policy_switches.h" | 28 #include "components/policy/core/common/policy_switches.h" |
29 #include "components/prefs/pref_service.h" | |
30 #include "components/signin/core/common/signin_pref_names.h" | |
31 #include "components/signin/core/common/signin_switches.h" | |
28 #include "content/public/browser/navigation_data.h" | 32 #include "content/public/browser/navigation_data.h" |
29 #include "content/public/browser/navigation_handle.h" | 33 #include "content/public/browser/navigation_handle.h" |
30 #include "content/public/browser/resource_dispatcher_host.h" | 34 #include "content/public/browser/resource_dispatcher_host.h" |
31 #include "content/public/browser/web_contents_observer.h" | 35 #include "content/public/browser/web_contents_observer.h" |
32 #include "content/public/test/browser_test_utils.h" | 36 #include "content/public/test/browser_test_utils.h" |
37 #include "net/base/io_buffer.h" | |
33 #include "net/http/http_request_headers.h" | 38 #include "net/http/http_request_headers.h" |
39 #include "net/http/http_response_headers.h" | |
40 #include "net/http/http_util.h" | |
34 #include "net/test/embedded_test_server/embedded_test_server.h" | 41 #include "net/test/embedded_test_server/embedded_test_server.h" |
35 #include "net/test/embedded_test_server/http_request.h" | 42 #include "net/test/embedded_test_server/http_request.h" |
36 #include "net/test/embedded_test_server/http_response.h" | 43 #include "net/test/embedded_test_server/http_response.h" |
37 #include "net/url_request/url_request.h" | 44 #include "net/url_request/url_request.h" |
45 #include "net/url_request/url_request_filter.h" | |
46 #include "net/url_request/url_request_interceptor.h" | |
47 #include "net/url_request/url_request_job.h" | |
48 #include "testing/gmock/include/gmock/gmock.h" | |
49 #include "testing/gtest/include/gtest/gtest.h" | |
38 | 50 |
39 using content::ResourceType; | 51 using content::ResourceType; |
52 using testing::HasSubstr; | |
53 using testing::Not; | |
40 | 54 |
41 namespace { | 55 namespace { |
42 static const char kTestPolicyHeader[] = "test_header"; | 56 static const char kTestPolicyHeader[] = "test_header"; |
43 static const char kServerRedirectUrl[] = "/server-redirect"; | 57 static const char kServerRedirectUrl[] = "/server-redirect"; |
44 | 58 |
45 std::unique_ptr<net::test_server::HttpResponse> HandleTestRequest( | 59 std::unique_ptr<net::test_server::HttpResponse> HandleTestRequest( |
46 const net::test_server::HttpRequest& request) { | 60 const net::test_server::HttpRequest& request) { |
47 if (base::StartsWith(request.relative_url, kServerRedirectUrl, | 61 if (base::StartsWith(request.relative_url, kServerRedirectUrl, |
48 base::CompareCase::SENSITIVE)) { | 62 base::CompareCase::SENSITIVE)) { |
49 // Extract the target URL and redirect there. | 63 // Extract the target URL and redirect there. |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
244 ui_test_utils::NavigateToURL( | 258 ui_test_utils::NavigateToURL( |
245 browser(), embedded_test_server()->GetURL("/google/google.html")); | 259 browser(), embedded_test_server()->GetURL("/google/google.html")); |
246 } | 260 } |
247 SetShouldAddDataReductionProxyData(true); | 261 SetShouldAddDataReductionProxyData(true); |
248 { | 262 { |
249 DidFinishNavigationObserver nav_observer( | 263 DidFinishNavigationObserver nav_observer( |
250 browser()->tab_strip_model()->GetActiveWebContents(), true); | 264 browser()->tab_strip_model()->GetActiveWebContents(), true); |
251 ui_test_utils::NavigateToURL(browser(), embedded_test_server()->base_url()); | 265 ui_test_utils::NavigateToURL(browser(), embedded_test_server()->base_url()); |
252 } | 266 } |
253 } | 267 } |
268 | |
269 namespace { | |
270 | |
271 // A mock URLRequestJob to that allows to inject specific response headers | |
272 // and a specific response body to a network request. | |
273 class MirrorMockURLRequestJob : public net::URLRequestJob { | |
sky
2016/08/18 19:29:50
Can you use some of the test support classes in ne
Ramin Halavati
2016/08/26 17:04:31
Done.
| |
274 public: | |
275 // Callback function on the UI thread to report a (URL, request headers) | |
276 // pair. Indicating that the |request headers| will be sent for the |URL|. | |
277 using ReportResponseHeadersOnUI = | |
278 base::Callback<void(const std::string&, const std::string&)>; | |
279 | |
280 MirrorMockURLRequestJob(net::URLRequest* request, | |
281 net::NetworkDelegate* network_delegate, | |
282 const std::string& response_headers, | |
283 const std::string& response_body, | |
284 ReportResponseHeadersOnUI report_on_ui) | |
285 : net::URLRequestJob(request, network_delegate), | |
286 response_headers_(response_headers), | |
287 response_body_(response_body), | |
288 response_body_offset_(0), | |
289 report_on_ui_(report_on_ui), | |
290 weak_factory_(this) {} | |
291 | |
292 void Start() override { | |
293 // Report the observed request headers on the UI thread. | |
294 content::BrowserThread::PostTask( | |
295 content::BrowserThread::UI, FROM_HERE, | |
296 base::Bind(report_on_ui_, request_->url().spec(), | |
297 request_->extra_request_headers().ToString())); | |
298 | |
299 // Start reading asynchronously so that all error reporting and data | |
300 // callbacks happen as they would for network requests. | |
301 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
302 FROM_HERE, base::Bind(&MirrorMockURLRequestJob::StartAsync, | |
303 weak_factory_.GetWeakPtr())); | |
304 } | |
305 | |
306 int ReadRawData(net::IOBuffer* buf, int buf_size) override { | |
307 size_t bytes_read = | |
308 std::min(static_cast<size_t>(buf_size), | |
309 response_body_.length() - response_body_offset_); | |
310 memcpy(buf->data(), response_body_.c_str() + response_body_offset_, | |
311 bytes_read); | |
312 response_body_offset_ += bytes_read; | |
313 return bytes_read; | |
314 } | |
315 | |
316 int GetResponseCode() const override { | |
317 net::HttpResponseInfo info; | |
318 GetResponseInfoConst(&info); | |
319 return info.headers->response_code(); | |
320 } | |
321 | |
322 void GetResponseInfo(net::HttpResponseInfo* info) override { | |
323 // Forward to private const version. | |
324 GetResponseInfoConst(info); | |
325 } | |
326 | |
327 protected: | |
328 void StartAsync() { | |
329 if (!request_) | |
330 return; | |
331 set_expected_content_size(response_body_.length()); | |
332 NotifyHeadersComplete(); | |
333 } | |
334 | |
335 // Private const version. | |
336 void GetResponseInfoConst(net::HttpResponseInfo* info) const { | |
337 // Send back mock headers. | |
338 std::string raw_headers; | |
339 raw_headers.append(response_headers_); | |
340 if (!response_body_.empty()) { | |
341 raw_headers.append(base::StringPrintf( | |
342 "Content-Length: %d\n", static_cast<int>(response_body_.length()))); | |
343 } | |
344 info->headers = | |
345 new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders( | |
346 raw_headers.c_str(), static_cast<int>(raw_headers.length()))); | |
347 } | |
348 | |
349 const std::string response_headers_; // All headers but 'Content-Length'. | |
350 const std::string response_body_; | |
351 size_t response_body_offset_; | |
352 const ReportResponseHeadersOnUI report_on_ui_; | |
353 base::WeakPtrFactory<MirrorMockURLRequestJob> weak_factory_; | |
354 }; | |
355 | |
356 // A URLRequestInterceptor to inject MirrorMockURLRequestJobs. | |
357 class MirrorMockJobInterceptor : public net::URLRequestInterceptor { | |
358 public: | |
359 using ReportResponseHeadersOnUI = | |
360 MirrorMockURLRequestJob::ReportResponseHeadersOnUI; | |
361 | |
362 MirrorMockJobInterceptor(const std::string& response_headers, | |
363 const std::string& response_body, | |
364 ReportResponseHeadersOnUI report_on_ui) | |
365 : response_headers_(response_headers), | |
366 response_body_(response_body), | |
367 report_on_ui_(report_on_ui){} | |
368 ~MirrorMockJobInterceptor() override = default; | |
369 | |
370 // URLRequestInterceptor implementation | |
371 net::URLRequestJob* MaybeInterceptRequest( | |
372 net::URLRequest* request, | |
373 net::NetworkDelegate* network_delegate) const override { | |
374 return new MirrorMockURLRequestJob(request, network_delegate, | |
375 response_headers_, response_body_, | |
376 report_on_ui_); | |
377 } | |
378 | |
379 static void Register(const GURL& url, | |
380 const std::string& response_headers, | |
381 const std::string& response_body, | |
382 ReportResponseHeadersOnUI report_on_ui) { | |
383 EXPECT_TRUE( | |
384 content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | |
385 net::URLRequestFilter::GetInstance()->AddHostnameInterceptor( | |
386 url.scheme(), url.host(), | |
387 base::WrapUnique(new MirrorMockJobInterceptor( | |
388 response_headers, response_body, report_on_ui))); | |
389 } | |
390 | |
391 static void Unregister(const GURL& url) { | |
392 EXPECT_TRUE( | |
393 content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | |
394 net::URLRequestFilter::GetInstance()->RemoveHostnameHandler(url.scheme(), | |
395 url.host()); | |
396 } | |
397 | |
398 private: | |
399 std::string response_headers_; | |
400 std::string response_body_; | |
401 ReportResponseHeadersOnUI report_on_ui_; | |
402 | |
403 DISALLOW_COPY_AND_ASSIGN(MirrorMockJobInterceptor); | |
404 }; | |
405 | |
406 void ReportRequestHeaders(std::map<std::string, std::string>* request_headers, | |
407 const std::string& url, | |
408 const std::string& headers) { | |
409 (*request_headers)[url] = headers; | |
410 } | |
411 | |
412 void EmptyClosure() {} | |
413 | |
414 } // namespace | |
415 | |
416 IN_PROC_BROWSER_TEST_F(ChromeResourceDispatcherHostDelegateBrowserTest, | |
417 MirrorRequestHeader) { | |
418 // Verify that X-Chrome-Connected is appended on Google domains if account | |
419 // consistency is enabled, but also that it is stripped in case a request | |
420 // is redirected to a non-google domain. | |
421 // This is a regression test for crbug.com/588492. | |
422 | |
423 // Enable account consistency so that mirror actually sets the | |
424 // X-Chrome-Connected header in requests to Google. | |
425 base::test::ScopedCommandLine command_line; | |
426 command_line.GetProcessCommandLine()->AppendSwitch( | |
427 switches::kEnableAccountConsistency); | |
428 | |
429 browser()->profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername, | |
430 "user@gmail.com"); | |
431 browser()->profile()->GetPrefs()->SetString( | |
432 prefs::kGoogleServicesUserAccountId, "account_id"); | |
433 | |
434 GURL google_com("http://www.google.com/"); | |
435 GURL redirected_com("http://www.redirected.com/"); | |
436 | |
437 // The HTTP Request headers (i.e. the ones that are managed on the URLRequest | |
438 // layer, not on the URLRequestJob layer) sent from the browser are collected | |
439 // in this map. The keys are URLs the values the request headers. | |
440 std::map<std::string, std::string> request_headers; | |
441 MirrorMockURLRequestJob::ReportResponseHeadersOnUI report_request_headers = | |
442 base::Bind(&ReportRequestHeaders, &request_headers); | |
443 | |
444 // Register MockJobInterceptors that redirect from google.com to | |
445 // redirected.com and serve static content on redirected.com. | |
446 content::BrowserThread::PostTask( | |
447 content::BrowserThread::IO, FROM_HERE, | |
448 base::Bind(&MirrorMockJobInterceptor::Register, google_com, | |
449 "HTTP/1.1 301 Moved Permanently\n" | |
450 "Location: http://www.redirected.com/\n", | |
451 std::string(), report_request_headers)); | |
452 content::BrowserThread::PostTask( | |
453 content::BrowserThread::IO, FROM_HERE, | |
454 base::Bind(&MirrorMockJobInterceptor::Register, redirected_com, | |
455 "HTTP/1.1 200 OK\n" | |
456 "Content-type: text/plain\n", | |
457 "success", report_request_headers)); | |
458 | |
459 // Perform a navigation to google.com to observe the request headers. | |
460 ui_test_utils::NavigateToURL(browser(), google_com); | |
461 | |
462 // Cleanup before verifying the observed headers. | |
463 content::BrowserThread::PostTask( | |
464 content::BrowserThread::IO, FROM_HERE, | |
465 base::Bind(&MirrorMockJobInterceptor::Unregister, redirected_com)); | |
466 content::BrowserThread::PostTask( | |
467 content::BrowserThread::IO, FROM_HERE, | |
468 base::Bind(&MirrorMockJobInterceptor::Unregister, google_com)); | |
469 | |
470 // Ensure that the response headers have been reported to the UI thread | |
471 // and unregistration has been processed on the IO thread. | |
472 base::RunLoop run_loop; | |
473 content::BrowserThread::PostTaskAndReply(content::BrowserThread::IO, | |
474 FROM_HERE, | |
475 // Flush IO thread... | |
476 base::Bind(&EmptyClosure), | |
477 // ... and UI thread. | |
478 run_loop.QuitClosure()); | |
479 run_loop.Run(); | |
480 | |
481 ASSERT_EQ(1u, request_headers.count(google_com.spec())); | |
482 EXPECT_THAT(request_headers[google_com.spec()], | |
483 HasSubstr("X-Chrome-Connected")); | |
484 ASSERT_EQ(1u, request_headers.count(redirected_com.spec())); | |
485 EXPECT_THAT(request_headers[redirected_com.spec()], | |
486 Not(HasSubstr("X-Chrome-Connected"))); | |
487 } | |
OLD | NEW |