Chromium Code Reviews| Index: net/url_request/url_request_unittest.cc |
| diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc |
| index 43d5d308f5c5a813e6d509ceabc4ac0e1bb7e935..b247fbd395152731387f0e52a0cf30ed4e3aaad6 100644 |
| --- a/net/url_request/url_request_unittest.cc |
| +++ b/net/url_request/url_request_unittest.cc |
| @@ -368,7 +368,8 @@ class BlockingNetworkDelegate : public TestNetworkDelegate { |
| URLRequest* request, |
| const CompletionCallback& callback, |
| const HttpResponseHeaders* original_response_headers, |
| - scoped_refptr<HttpResponseHeaders>* override_response_headers) OVERRIDE; |
| + scoped_refptr<HttpResponseHeaders>* override_response_headers, |
| + GURL* allowed_unsafe_redirect_url) OVERRIDE; |
| virtual NetworkDelegate::AuthRequiredResponse OnAuthRequired( |
| URLRequest* request, |
| @@ -391,7 +392,7 @@ class BlockingNetworkDelegate : public TestNetworkDelegate { |
| int retval_; // To be returned in non-auth stages. |
| AuthRequiredResponse auth_retval_; |
| - GURL redirect_url_; // Used if non-empty. |
| + GURL redirect_url_; // Used if non-empty during OnBeforeURLRequest. |
| int block_on_; // Bit mask: in which stages to block. |
| // |auth_credentials_| will be copied to |*target_auth_credential_| on |
| @@ -483,10 +484,13 @@ int BlockingNetworkDelegate::OnHeadersReceived( |
| URLRequest* request, |
| const CompletionCallback& callback, |
| const HttpResponseHeaders* original_response_headers, |
| - scoped_refptr<HttpResponseHeaders>* override_response_headers) { |
| - TestNetworkDelegate::OnHeadersReceived( |
| - request, callback, original_response_headers, |
| - override_response_headers); |
| + scoped_refptr<HttpResponseHeaders>* override_response_headers, |
| + GURL* allowed_unsafe_redirect_url) { |
| + TestNetworkDelegate::OnHeadersReceived(request, |
| + callback, |
| + original_response_headers, |
| + override_response_headers, |
| + allowed_unsafe_redirect_url); |
| return MaybeBlockStage(ON_HEADERS_RECEIVED, callback); |
| } |
| @@ -2417,8 +2421,8 @@ class FixedDateNetworkDelegate : public TestNetworkDelegate { |
| net::URLRequest* request, |
| const net::CompletionCallback& callback, |
| const net::HttpResponseHeaders* original_response_headers, |
| - scoped_refptr<net::HttpResponseHeaders>* override_response_headers) |
| - OVERRIDE; |
| + scoped_refptr<net::HttpResponseHeaders>* override_response_headers, |
| + GURL* allowed_unsafe_redirect_url) OVERRIDE; |
| private: |
| std::string fixed_date_; |
| @@ -2430,7 +2434,8 @@ int FixedDateNetworkDelegate::OnHeadersReceived( |
| net::URLRequest* request, |
| const net::CompletionCallback& callback, |
| const net::HttpResponseHeaders* original_response_headers, |
| - scoped_refptr<net::HttpResponseHeaders>* override_response_headers) { |
| + scoped_refptr<net::HttpResponseHeaders>* override_response_headers, |
| + GURL* allowed_unsafe_redirect_url) { |
| net::HttpResponseHeaders* new_response_headers = |
| new net::HttpResponseHeaders(original_response_headers->raw_headers()); |
| @@ -2441,7 +2446,8 @@ int FixedDateNetworkDelegate::OnHeadersReceived( |
| return TestNetworkDelegate::OnHeadersReceived(request, |
| callback, |
| original_response_headers, |
| - override_response_headers); |
| + override_response_headers, |
| + allowed_unsafe_redirect_url); |
| } |
| // Test that cookie expiration times are adjusted for server/client clock |
| @@ -2697,6 +2703,59 @@ class URLRequestTestHTTP : public URLRequestTest { |
| LocalHttpTestServer test_server_; |
| }; |
| +// Tests that redirection to an unsafe URL is allowed when it has been marked as |
| +// safe. |
| +TEST_F(URLRequestTestHTTP, UnsafeRedirectToWhitelistedUnsafeURL) { |
| + ASSERT_TRUE(test_server_.Start()); |
| + |
| + GURL unsafe_url("data:text/html,this-is-considered-an-unsafe-url"); |
| + default_network_delegate_.set_redirect_on_headers_received_url(unsafe_url); |
| + default_network_delegate_.set_allowed_unsafe_redirect_url(unsafe_url); |
| + |
| + TestDelegate d; |
| + { |
| + URLRequest r(test_server_.GetURL("whatever"), |
| + DEFAULT_PRIORITY, |
| + &d, |
| + &default_context_); |
| + |
| + r.Start(); |
| + base::RunLoop().Run(); |
| + |
| + EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status()); |
| + |
| + EXPECT_EQ(2U, r.url_chain().size()); |
| + EXPECT_EQ(0, r.status().error()); |
|
mmenke
2014/03/25 15:08:34
This should be net::OK instead of 0.
robwu
2014/03/25 15:59:35
Done.
|
| + EXPECT_EQ(unsafe_url, r.url()); |
|
mmenke
2014/03/25 15:08:34
Suggest checking the body, for completeness.
robwu
2014/03/25 15:59:35
Done.
|
| + } |
| +} |
| + |
| +// Tests that a redirect to a different unsafe URL is blocked, even after adding |
| +// some other URL to the whitelist. |
| +TEST_F(URLRequestTestHTTP, UnsafeRedirectToDifferentUnsafeURL) { |
| + ASSERT_TRUE(test_server_.Start()); |
| + |
| + GURL unsafe_url("data:text/html,something"); |
| + GURL different_unsafe_url("data:text/html,something-else"); |
| + default_network_delegate_.set_redirect_on_headers_received_url(unsafe_url); |
| + default_network_delegate_.set_allowed_unsafe_redirect_url( |
| + different_unsafe_url); |
| + |
| + TestDelegate d; |
| + { |
| + URLRequest r(test_server_.GetURL("whatever"), |
| + DEFAULT_PRIORITY, |
| + &d, |
| + &default_context_); |
| + |
| + r.Start(); |
| + base::RunLoop().Run(); |
| + |
| + EXPECT_EQ(URLRequestStatus::FAILED, r.status().status()); |
| + EXPECT_EQ(ERR_UNSAFE_REDIRECT, r.status().error()); |
| + } |
| +} |
|
mmenke
2014/03/25 15:08:34
Sorry, there were two parts to my comment (I shoul
robwu
2014/03/25 15:59:35
Done.
|
| + |
| // In this unit test, we're using the HTTPTestServer as a proxy server and |
| // issuing a CONNECT request with the magic host name "www.redirect.com". |
| // The HTTPTestServer will return a 302 response, which we should not |
| @@ -3008,6 +3067,39 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateRedirectRequestPost) { |
| EXPECT_EQ(1, network_delegate.destroyed_requests()); |
| } |
| +// Tests that the network delegate can block and redirect a request to a new |
| +// URL during OnHeadersReceived. |
| +TEST_F(URLRequestTestHTTP, NetworkDelegateRedirectRequestOnHeadersReceived) { |
| + ASSERT_TRUE(test_server_.Start()); |
| + |
| + TestDelegate d; |
| + BlockingNetworkDelegate network_delegate( |
| + BlockingNetworkDelegate::AUTO_CALLBACK); |
| + network_delegate.set_block_on(BlockingNetworkDelegate::ON_HEADERS_RECEIVED); |
| + GURL redirect_url(test_server_.GetURL("simple.html")); |
| + network_delegate.set_redirect_on_headers_received_url(redirect_url); |
| + |
| + TestURLRequestContextWithProxy context( |
| + test_server_.host_port_pair().ToString(), &network_delegate); |
| + |
| + { |
| + GURL original_url(test_server_.GetURL("empty.html")); |
| + URLRequest r(original_url, DEFAULT_PRIORITY, &d, &context); |
| + |
| + r.Start(); |
| + base::RunLoop().Run(); |
| + |
| + EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status()); |
| + EXPECT_EQ(0, r.status().error()); |
| + EXPECT_EQ(redirect_url, r.url()); |
| + EXPECT_EQ(original_url, r.original_url()); |
| + EXPECT_EQ(2U, r.url_chain().size()); |
| + EXPECT_EQ(2, network_delegate.created_requests()); |
| + EXPECT_EQ(0, network_delegate.destroyed_requests()); |
| + } |
| + EXPECT_EQ(1, network_delegate.destroyed_requests()); |
| +} |
| + |
| // Tests that the network delegate can synchronously complete OnAuthRequired |
| // by taking no action. This indicates that the NetworkDelegate does not want to |
| // handle the challenge, and is passing the buck along to the |
| @@ -3920,10 +4012,13 @@ class AsyncLoggingNetworkDelegate : public TestNetworkDelegate { |
| URLRequest* request, |
| const CompletionCallback& callback, |
| const HttpResponseHeaders* original_response_headers, |
| - scoped_refptr<HttpResponseHeaders>* override_response_headers) OVERRIDE { |
| - TestNetworkDelegate::OnHeadersReceived(request, callback, |
| + scoped_refptr<HttpResponseHeaders>* override_response_headers, |
| + GURL* allowed_unsafe_redirect_url) OVERRIDE { |
| + TestNetworkDelegate::OnHeadersReceived(request, |
| + callback, |
| original_response_headers, |
| - override_response_headers); |
| + override_response_headers, |
| + allowed_unsafe_redirect_url); |
| return RunCallbackAsynchronously(request, callback); |
| } |
| @@ -5235,6 +5330,62 @@ TEST_F(URLRequestTestHTTP, NoCacheOnNetworkDelegateRedirect) { |
| } |
| } |
| +// |
| +// Redirects from an URL with fragment to an unsafe URL without fragment should |
| +// be allowed. |
| +TEST_F(URLRequestTestHTTP, UnsafeRedirectWithReferenceFragment) { |
| + ASSERT_TRUE(test_server_.Start()); |
| + |
| + GURL original_url(test_server_.GetURL("original#fragment")); |
| + GURL unsafe_url("data:,url-marked-safe-and-used-in-redirect"); |
| + GURL expected_url("data:,url-marked-safe-and-used-in-redirect#fragment"); |
| + |
| + default_network_delegate_.set_redirect_on_headers_received_url(unsafe_url); |
| + default_network_delegate_.set_allowed_unsafe_redirect_url(unsafe_url); |
| + |
| + TestDelegate d; |
| + { |
| + URLRequest r(original_url, DEFAULT_PRIORITY, &d, &default_context_); |
| + |
| + r.Start(); |
| + base::RunLoop().Run(); |
| + |
| + EXPECT_EQ(2U, r.url_chain().size()); |
| + EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status()); |
| + EXPECT_EQ(0, r.status().error()); |
| + EXPECT_EQ(original_url, r.original_url()); |
| + EXPECT_EQ(expected_url, r.url()); |
| + } |
| +} |
| + |
| +// When a delegate has specified a safe redirect URL, but it does not match the |
| +// redirect target, then do not prevent the reference fragment from being added. |
| +TEST_F(URLRequestTestHTTP, RedirectWithReferenceFragment) { |
| + ASSERT_TRUE(test_server_.Start()); |
| + |
| + GURL original_url(test_server_.GetURL("original#expected-fragment")); |
| + GURL unsafe_url("data:text/html,this-url-does-not-match-redirect-url"); |
| + GURL redirect_url(test_server_.GetURL("target")); |
| + GURL expected_redirect_url(test_server_.GetURL("target#expected-fragment")); |
| + |
| + default_network_delegate_.set_redirect_on_headers_received_url(redirect_url); |
| + default_network_delegate_.set_allowed_unsafe_redirect_url(unsafe_url); |
| + |
| + TestDelegate d; |
| + { |
| + URLRequest r(original_url, DEFAULT_PRIORITY, &d, &default_context_); |
| + |
| + r.Start(); |
| + base::RunLoop().Run(); |
| + |
| + EXPECT_EQ(2U, r.url_chain().size()); |
| + EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status()); |
| + EXPECT_EQ(0, r.status().error()); |
| + EXPECT_EQ(original_url, r.original_url()); |
| + EXPECT_EQ(expected_redirect_url, r.url()); |
| + } |
| +} |
| + |
| TEST_F(URLRequestTestHTTP, NoUserPassInReferrer) { |
| ASSERT_TRUE(test_server_.Start()); |