| 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..9d90cf82801c9e52f49c4ba04aa3276360713dfa 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
|
| @@ -3008,6 +3014,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(net::OK, 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 +3959,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 +5277,142 @@ TEST_F(URLRequestTestHTTP, NoCacheOnNetworkDelegateRedirect) {
|
| }
|
| }
|
|
|
| +// 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(net::OK, r.status().error());
|
| + EXPECT_EQ(unsafe_url, r.url());
|
| + EXPECT_EQ("this-is-considered-an-unsafe-url", d.data_received());
|
| + }
|
| +}
|
| +
|
| +// 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());
|
| + }
|
| +}
|
| +
|
| +// 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(net::OK, r.status().error());
|
| + EXPECT_EQ(original_url, r.original_url());
|
| + EXPECT_EQ(expected_url, r.url());
|
| + }
|
| +}
|
| +
|
| +// Redirects from an URL with fragment to an unsafe URL with fragment should
|
| +// be allowed, and the reference fragment of the target URL should be preserved.
|
| +TEST_F(URLRequestTestHTTP, UnsafeRedirectWithDifferentReferenceFragment) {
|
| + ASSERT_TRUE(test_server_.Start());
|
| +
|
| + GURL original_url(test_server_.GetURL("original#fragment1"));
|
| + GURL unsafe_url("data:,url-marked-safe-and-used-in-redirect#fragment2");
|
| + GURL expected_url("data:,url-marked-safe-and-used-in-redirect#fragment2");
|
| +
|
| + 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(net::OK, 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(net::OK, 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());
|
|
|
|
|