Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / net / url_request / url_request_unittest.cc
index daf4c57..7a526a3 100644 (file)
@@ -16,6 +16,7 @@
 #include "base/bind.h"
 #include "base/compiler_specific.h"
 #include "base/file_util.h"
+#include "base/files/scoped_temp_dir.h"
 #include "base/format_macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop.h"
@@ -29,6 +30,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "net/base/capturing_net_log.h"
+#include "net/base/filename_util.h"
 #include "net/base/load_flags.h"
 #include "net/base/load_timing_info.h"
 #include "net/base/load_timing_info_test_util.h"
 #include "net/base/upload_data_stream.h"
 #include "net/base/upload_file_element_reader.h"
 #include "net/cert/ev_root_ca_metadata.h"
+#include "net/cert/mock_cert_verifier.h"
 #include "net/cert/test_root_certs.h"
 #include "net/cookies/cookie_monster.h"
 #include "net/cookies/cookie_store_test_helpers.h"
 #include "net/disk_cache/disk_cache.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/ftp/ftp_network_layer.h"
+#include "net/http/http_byte_range.h"
 #include "net/http/http_cache.h"
 #include "net/http/http_network_layer.h"
 #include "net/http/http_network_session.h"
 #include "net/http/http_request_headers.h"
 #include "net/http/http_response_headers.h"
+#include "net/http/http_util.h"
 #include "net/ocsp/nss_ocsp.h"
 #include "net/proxy/proxy_service.h"
 #include "net/socket/ssl_client_socket.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/spawned_test_server/spawned_test_server.h"
 #include "net/url_request/data_protocol_handler.h"
-#include "net/url_request/file_protocol_handler.h"
-#include "net/url_request/ftp_protocol_handler.h"
 #include "net/url_request/static_http_user_agent_settings.h"
 #include "net/url_request/url_request.h"
-#include "net/url_request/url_request_file_dir_job.h"
 #include "net/url_request/url_request_http_job.h"
 #include "net/url_request/url_request_job_factory_impl.h"
 #include "net/url_request/url_request_redirect_job.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 
+#if !defined(DISABLE_FILE_SUPPORT)
+#include "net/url_request/file_protocol_handler.h"
+#include "net/url_request/url_request_file_dir_job.h"
+#endif
+
+#if !defined(DISABLE_FTP_SUPPORT)
+#include "net/url_request/ftp_protocol_handler.h"
+#endif
+
 #if defined(OS_WIN)
 #include "base/win/scoped_com_initializer.h"
 #include "base/win/scoped_comptr.h"
 #include "base/win/windows_version.h"
 #endif
 
+using base::ASCIIToUTF16;
 using base::Time;
 
 namespace net {
@@ -160,6 +172,26 @@ void TestLoadTimingReusedWithProxy(
 
 // Tests load timing information in the case of a cache hit, when no cache
 // validation request was sent over the wire.
+base::StringPiece TestNetResourceProvider(int key) {
+  return "header";
+}
+
+void FillBuffer(char* buffer, size_t len) {
+  static bool called = false;
+  if (!called) {
+    called = true;
+    int seed = static_cast<int>(Time::Now().ToInternalValue());
+    srand(seed);
+  }
+
+  for (size_t i = 0; i < len; i++) {
+    buffer[i] = static_cast<char>(rand());
+    if (!buffer[i])
+      buffer[i] = 'g';
+  }
+}
+
+#if !defined(OS_IOS)
 void TestLoadTimingCacheHitNoNetwork(
     const net::LoadTimingInfo& load_timing_info) {
   EXPECT_FALSE(load_timing_info.socket_reused);
@@ -197,10 +229,6 @@ void TestLoadTimingNoHttpResponse(
   EXPECT_TRUE(load_timing_info.receive_headers_end.is_null());
 }
 
-base::StringPiece TestNetResourceProvider(int key) {
-  return "header";
-}
-
 // Do a case-insensitive search through |haystack| for |needle|.
 bool ContainsString(const std::string& haystack, const char* needle) {
   std::string::const_iterator it =
@@ -212,21 +240,6 @@ bool ContainsString(const std::string& haystack, const char* needle) {
   return it != haystack.end();
 }
 
-void FillBuffer(char* buffer, size_t len) {
-  static bool called = false;
-  if (!called) {
-    called = true;
-    int seed = static_cast<int>(Time::Now().ToInternalValue());
-    srand(seed);
-  }
-
-  for (size_t i = 0; i < len; i++) {
-    buffer[i] = static_cast<char>(rand());
-    if (!buffer[i])
-      buffer[i] = 'g';
-  }
-}
-
 UploadDataStream* CreateSimpleUploadData(const char* data) {
   scoped_ptr<UploadElementReader> reader(
       new UploadBytesElementReader(data, strlen(data)));
@@ -235,14 +248,6 @@ UploadDataStream* CreateSimpleUploadData(const char* data) {
 
 // Verify that the SSLInfo of a successful SSL connection has valid values.
 void CheckSSLInfo(const SSLInfo& ssl_info) {
-  // Allow ChromeFrame fake SSLInfo to get through.
-  if (ssl_info.cert.get() &&
-      ssl_info.cert.get()->issuer().GetDisplayName() == "Chrome Internal") {
-    // -1 means unknown.
-    EXPECT_EQ(ssl_info.security_bits, -1);
-    return;
-  }
-
   // -1 means unknown.  0 means no encryption.
   EXPECT_GT(ssl_info.security_bits, 0);
 
@@ -276,6 +281,7 @@ bool FingerprintsEqual(const HashValueVector& a, const HashValueVector& b) {
 
   return true;
 }
+#endif  // !defined(OS_IOS)
 
 // A network delegate that allows the user to choose a subset of request stages
 // to block in. When blocking, the delegate can do one of the following:
@@ -369,7 +375,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,
@@ -392,7 +399,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
@@ -484,10 +491,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);
 }
@@ -594,8 +604,10 @@ class URLRequestTest : public PlatformTest {
     default_context_.set_network_delegate(&default_network_delegate_);
     default_context_.set_net_log(&net_log_);
     job_factory_.SetProtocolHandler("data", new DataProtocolHandler);
+#if !defined(DISABLE_FILE_SUPPORT)
     job_factory_.SetProtocolHandler(
         "file", new FileProtocolHandler(base::MessageLoopProxy::current()));
+#endif
     default_context_.set_job_factory(&job_factory_);
     default_context_.Init();
   }
@@ -700,7 +712,7 @@ TEST_F(URLRequestTest, FileTest) {
     base::RunLoop().Run();
 
     int64 file_size = -1;
-    EXPECT_TRUE(file_util::GetFileSize(app_path, &file_size));
+    EXPECT_TRUE(base::GetFileSize(app_path, &file_size));
 
     EXPECT_TRUE(!r.is_pending());
     EXPECT_EQ(1, d.response_started_count());
@@ -738,12 +750,12 @@ TEST_F(URLRequestTest, FileTestFullSpecifiedRange) {
   FillBuffer(buffer.get(), buffer_size);
 
   base::FilePath temp_path;
-  EXPECT_TRUE(file_util::CreateTemporaryFile(&temp_path));
+  EXPECT_TRUE(base::CreateTemporaryFile(&temp_path));
   GURL temp_url = FilePathToFileURL(temp_path);
-  EXPECT_TRUE(file_util::WriteFile(temp_path, buffer.get(), buffer_size));
+  EXPECT_TRUE(base::WriteFile(temp_path, buffer.get(), buffer_size));
 
   int64 file_size;
-  EXPECT_TRUE(file_util::GetFileSize(temp_path, &file_size));
+  EXPECT_TRUE(base::GetFileSize(temp_path, &file_size));
 
   const size_t first_byte_position = 500;
   const size_t last_byte_position = buffer_size - first_byte_position;
@@ -756,10 +768,10 @@ TEST_F(URLRequestTest, FileTestFullSpecifiedRange) {
     URLRequest r(temp_url, DEFAULT_PRIORITY, &d, &default_context_);
 
     HttpRequestHeaders headers;
-    headers.SetHeader(HttpRequestHeaders::kRange,
-                      base::StringPrintf(
-                           "bytes=%" PRIuS "-%" PRIuS,
-                           first_byte_position, last_byte_position));
+    headers.SetHeader(
+        HttpRequestHeaders::kRange,
+        net::HttpByteRange::Bounded(
+            first_byte_position, last_byte_position).GetHeaderValue());
     r.SetExtraRequestHeaders(headers);
     r.Start();
     EXPECT_TRUE(r.is_pending());
@@ -782,12 +794,12 @@ TEST_F(URLRequestTest, FileTestHalfSpecifiedRange) {
   FillBuffer(buffer.get(), buffer_size);
 
   base::FilePath temp_path;
-  EXPECT_TRUE(file_util::CreateTemporaryFile(&temp_path));
+  EXPECT_TRUE(base::CreateTemporaryFile(&temp_path));
   GURL temp_url = FilePathToFileURL(temp_path);
-  EXPECT_TRUE(file_util::WriteFile(temp_path, buffer.get(), buffer_size));
+  EXPECT_TRUE(base::WriteFile(temp_path, buffer.get(), buffer_size));
 
   int64 file_size;
-  EXPECT_TRUE(file_util::GetFileSize(temp_path, &file_size));
+  EXPECT_TRUE(base::GetFileSize(temp_path, &file_size));
 
   const size_t first_byte_position = 500;
   const size_t last_byte_position = buffer_size - 1;
@@ -801,8 +813,8 @@ TEST_F(URLRequestTest, FileTestHalfSpecifiedRange) {
 
     HttpRequestHeaders headers;
     headers.SetHeader(HttpRequestHeaders::kRange,
-                      base::StringPrintf("bytes=%" PRIuS "-",
-                                         first_byte_position));
+                      net::HttpByteRange::RightUnbounded(
+                          first_byte_position).GetHeaderValue());
     r.SetExtraRequestHeaders(headers);
     r.Start();
     EXPECT_TRUE(r.is_pending());
@@ -825,20 +837,19 @@ TEST_F(URLRequestTest, FileTestMultipleRanges) {
   FillBuffer(buffer.get(), buffer_size);
 
   base::FilePath temp_path;
-  EXPECT_TRUE(file_util::CreateTemporaryFile(&temp_path));
+  EXPECT_TRUE(base::CreateTemporaryFile(&temp_path));
   GURL temp_url = FilePathToFileURL(temp_path);
-  EXPECT_TRUE(file_util::WriteFile(temp_path, buffer.get(), buffer_size));
+  EXPECT_TRUE(base::WriteFile(temp_path, buffer.get(), buffer_size));
 
   int64 file_size;
-  EXPECT_TRUE(file_util::GetFileSize(temp_path, &file_size));
+  EXPECT_TRUE(base::GetFileSize(temp_path, &file_size));
 
   TestDelegate d;
   {
     URLRequest r(temp_url, DEFAULT_PRIORITY, &d, &default_context_);
 
     HttpRequestHeaders headers;
-    headers.SetHeader(HttpRequestHeaders::kRange,
-                      "bytes=0-0,10-200,200-300");
+    headers.SetHeader(HttpRequestHeaders::kRange, "bytes=0-0,10-200,200-300");
     r.SetExtraRequestHeaders(headers);
     r.Start();
     EXPECT_TRUE(r.is_pending());
@@ -850,6 +861,40 @@ TEST_F(URLRequestTest, FileTestMultipleRanges) {
   EXPECT_TRUE(base::DeleteFile(temp_path, false));
 }
 
+TEST_F(URLRequestTest, AllowFileURLs) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath test_file;
+  ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.path(), &test_file));
+  std::string test_data("monkey");
+  base::WriteFile(test_file, test_data.data(), test_data.size());
+  GURL test_file_url = net::FilePathToFileURL(test_file);
+
+  {
+    TestDelegate d;
+    TestNetworkDelegate network_delegate;
+    network_delegate.set_can_access_files(true);
+    default_context_.set_network_delegate(&network_delegate);
+    URLRequest r(test_file_url, DEFAULT_PRIORITY, &d, &default_context_);
+    r.Start();
+    base::RunLoop().Run();
+    EXPECT_FALSE(d.request_failed());
+    EXPECT_EQ(test_data, d.data_received());
+  }
+
+  {
+    TestDelegate d;
+    TestNetworkDelegate network_delegate;
+    network_delegate.set_can_access_files(false);
+    default_context_.set_network_delegate(&network_delegate);
+    URLRequest r(test_file_url, DEFAULT_PRIORITY, &d, &default_context_);
+    r.Start();
+    base::RunLoop().Run();
+    EXPECT_TRUE(d.request_failed());
+    EXPECT_EQ("", d.data_received());
+  }
+}
+
 TEST_F(URLRequestTest, InvalidUrlTest) {
   TestDelegate d;
   {
@@ -970,8 +1015,8 @@ TEST_F(URLRequestTest, FileDirOutputSanity) {
 
   // Generate entry for the sentinel file.
   base::FilePath sentinel_path = path.AppendASCII(sentinel_name);
-  base::PlatformFileInfo info;
-  EXPECT_TRUE(file_util::GetFileInfo(sentinel_path, &info));
+  base::File::Info info;
+  EXPECT_TRUE(base::GetFileInfo(sentinel_path, &info));
   EXPECT_GT(info.size, 0);
   std::string sentinel_output = GetDirectoryListingEntry(
       base::string16(sentinel_name, sentinel_name + strlen(sentinel_name)),
@@ -1896,11 +1941,37 @@ TEST_F(URLRequestTest, SetJobPriority) {
   EXPECT_EQ(MEDIUM, job->priority());
 }
 
+// Setting the IGNORE_LIMITS load flag should be okay if the priority
+// is MAXIMUM_PRIORITY.
+TEST_F(URLRequestTest, PriorityIgnoreLimits) {
+  TestDelegate d;
+  URLRequest req(GURL("http://test_intercept/foo"),
+                 MAXIMUM_PRIORITY,
+                 &d,
+                 &default_context_);
+  EXPECT_EQ(MAXIMUM_PRIORITY, req.priority());
+
+  scoped_refptr<URLRequestTestJob> job =
+      new URLRequestTestJob(&req, &default_network_delegate_);
+  AddTestInterceptor()->set_main_intercept_job(job.get());
+
+  req.SetLoadFlags(LOAD_IGNORE_LIMITS);
+  EXPECT_EQ(MAXIMUM_PRIORITY, req.priority());
+
+  req.SetPriority(MAXIMUM_PRIORITY);
+  EXPECT_EQ(MAXIMUM_PRIORITY, req.priority());
+
+  req.Start();
+  EXPECT_EQ(MAXIMUM_PRIORITY, req.priority());
+  EXPECT_EQ(MAXIMUM_PRIORITY, job->priority());
+}
+
 // TODO(droger): Support SpawnedTestServer on iOS (see http://crbug.com/148666).
 #if !defined(OS_IOS)
 // A subclass of SpawnedTestServer that uses a statically-configured hostname.
 // This is to work around mysterious failures in chrome_frame_net_tests. See:
 // http://crbug.com/114369
+// TODO(erikwright): remove or update as needed; see http://crbug.com/334634.
 class LocalHttpTestServer : public SpawnedTestServer {
  public:
   explicit LocalHttpTestServer(const base::FilePath& document_root)
@@ -2004,7 +2075,7 @@ TEST_F(URLRequestTest, DoNotSendCookies) {
                    DEFAULT_PRIORITY,
                    &d,
                    &default_context_);
-    req.set_load_flags(LOAD_DO_NOT_SEND_COOKIES);
+    req.SetLoadFlags(LOAD_DO_NOT_SEND_COOKIES);
     req.Start();
     base::RunLoop().Run();
 
@@ -2048,7 +2119,7 @@ TEST_F(URLRequestTest, DoNotSaveCookies) {
         DEFAULT_PRIORITY,
         &d,
         &default_context_);
-    req.set_load_flags(LOAD_DO_NOT_SAVE_COOKIES);
+    req.SetLoadFlags(LOAD_DO_NOT_SAVE_COOKIES);
     req.Start();
 
     base::RunLoop().Run();
@@ -2359,8 +2430,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_;
@@ -2372,7 +2443,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());
 
@@ -2383,7 +2455,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
@@ -2490,7 +2563,7 @@ TEST_F(URLRequestTest, DoNotOverrideReferrer) {
     HttpRequestHeaders headers;
     headers.SetHeader(HttpRequestHeaders::kReferer, "http://bar.com/");
     req.SetExtraRequestHeaders(headers);
-    req.set_load_flags(LOAD_VALIDATE_CACHE);
+    req.SetLoadFlags(LOAD_VALIDATE_CACHE);
 
     req.Start();
     base::RunLoop().Run();
@@ -2626,10 +2699,7 @@ class URLRequestTestHTTP : public URLRequestTest {
     bool is_success = r.status().is_success();
 
     if (!is_success) {
-      // Requests handled by ChromeFrame send a less precise error message,
-      // ERR_CONNECTION_ABORTED.
-      EXPECT_TRUE(r.status().error() == ERR_RESPONSE_HEADERS_TOO_BIG ||
-                  r.status().error() == ERR_CONNECTION_ABORTED);
+      EXPECT_TRUE(r.status().error() == ERR_RESPONSE_HEADERS_TOO_BIG);
       // The test server appears to be unable to handle subsequent requests
       // after this error is triggered. Force it to restart.
       EXPECT_TRUE(test_server_.Stop());
@@ -2953,6 +3023,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
@@ -3763,6 +3866,22 @@ class AsyncDelegateLogger : public base::RefCounted<AsyncDelegateLogger> {
     return log_position + 1;
   }
 
+  // Find delegate request begin and end messages for OnBeforeNetworkStart.
+  // Returns the position of the end message.
+  static size_t ExpectBeforeNetworkEvents(
+      const CapturingNetLog::CapturedEntryList& entries,
+      size_t log_position) {
+    log_position =
+        ExpectLogContainsSomewhereAfter(entries,
+                                        log_position,
+                                        NetLog::TYPE_URL_REQUEST_DELEGATE,
+                                        NetLog::PHASE_BEGIN);
+    EXPECT_EQ(NetLog::TYPE_URL_REQUEST_DELEGATE,
+              entries[log_position + 1].type);
+    EXPECT_EQ(NetLog::PHASE_END, entries[log_position + 1].phase);
+    return log_position + 1;
+  }
+
  private:
   friend class base::RefCounted<AsyncDelegateLogger>;
 
@@ -3781,8 +3900,7 @@ class AsyncDelegateLogger : public base::RefCounted<AsyncDelegateLogger> {
   ~AsyncDelegateLogger() {}
 
   void Start() {
-    url_request_->SetDelegateInfo(kFirstDelegateInfo,
-                                  URLRequest::DELEGATE_INFO_DEBUG_ONLY);
+    url_request_->LogBlockedBy(kFirstDelegateInfo);
     LoadStateWithParam load_state = url_request_->GetLoadState();
     EXPECT_EQ(expected_first_load_state_, load_state.state);
     EXPECT_NE(ASCIIToUTF16(kFirstDelegateInfo), load_state.param);
@@ -3792,8 +3910,7 @@ class AsyncDelegateLogger : public base::RefCounted<AsyncDelegateLogger> {
   }
 
   void LogSecondDelegate() {
-    url_request_->SetDelegateInfo(kSecondDelegateInfo,
-                                  URLRequest::DELEGATE_INFO_DISPLAY_TO_USER);
+    url_request_->LogAndReportBlockedBy(kSecondDelegateInfo);
     LoadStateWithParam load_state = url_request_->GetLoadState();
     EXPECT_EQ(expected_second_load_state_, load_state.state);
     if (expected_second_load_state_ == LOAD_STATE_WAITING_FOR_DELEGATE) {
@@ -3807,12 +3924,11 @@ class AsyncDelegateLogger : public base::RefCounted<AsyncDelegateLogger> {
   }
 
   void LogComplete() {
-    url_request_->SetDelegateInfo(
-        NULL, URLRequest::DELEGATE_INFO_DISPLAY_TO_USER);
+    url_request_->LogUnblocked();
     LoadStateWithParam load_state = url_request_->GetLoadState();
     EXPECT_EQ(expected_third_load_state_, load_state.state);
     if (expected_second_load_state_ == LOAD_STATE_WAITING_FOR_DELEGATE)
-      EXPECT_EQ(string16(), load_state.param);
+      EXPECT_EQ(base::string16(), load_state.param);
     callback_.Run();
   }
 
@@ -3852,10 +3968,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);
   }
 
@@ -4004,7 +4123,7 @@ TEST_F(URLRequestTestHTTP, DelegateInfoBeforeStart) {
                  &context);
     LoadStateWithParam load_state = r.GetLoadState();
     EXPECT_EQ(LOAD_STATE_IDLE, load_state.state);
-    EXPECT_EQ(string16(), load_state.param);
+    EXPECT_EQ(base::string16(), load_state.param);
 
     AsyncDelegateLogger::Run(
         &r,
@@ -4052,7 +4171,7 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateInfo) {
                  &context);
     LoadStateWithParam load_state = r.GetLoadState();
     EXPECT_EQ(LOAD_STATE_IDLE, load_state.state);
-    EXPECT_EQ(string16(), load_state.param);
+    EXPECT_EQ(base::string16(), load_state.param);
 
     r.Start();
     base::RunLoop().Run();
@@ -4080,6 +4199,11 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateInfo) {
     ASSERT_LT(log_position, entries.size());
     EXPECT_EQ(NetLog::TYPE_URL_REQUEST_DELEGATE, entries[log_position].type);
     EXPECT_EQ(NetLog::PHASE_END, entries[log_position].phase);
+
+    if (i == 1) {
+      log_position = AsyncDelegateLogger::ExpectBeforeNetworkEvents(
+          entries, log_position + 1);
+    }
   }
 
   EXPECT_FALSE(LogContainsEntryWithTypeAfter(
@@ -4105,7 +4229,7 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateInfoRedirect) {
                  &context);
     LoadStateWithParam load_state = r.GetLoadState();
     EXPECT_EQ(LOAD_STATE_IDLE, load_state.state);
-    EXPECT_EQ(string16(), load_state.param);
+    EXPECT_EQ(base::string16(), load_state.param);
 
     r.Start();
     base::RunLoop().Run();
@@ -4135,6 +4259,11 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateInfoRedirect) {
     ASSERT_LT(log_position, entries.size());
     EXPECT_EQ(NetLog::TYPE_URL_REQUEST_DELEGATE, entries[log_position].type);
     EXPECT_EQ(NetLog::PHASE_END, entries[log_position].phase);
+
+    if (i == 1) {
+      log_position = AsyncDelegateLogger::ExpectBeforeNetworkEvents(
+          entries, log_position + 1);
+    }
   }
 
   // The URLRequest::Delegate then gets informed about the redirect.
@@ -4183,7 +4312,7 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateInfoAuth) {
                  &context);
     LoadStateWithParam load_state = r.GetLoadState();
     EXPECT_EQ(LOAD_STATE_IDLE, load_state.state);
-    EXPECT_EQ(string16(), load_state.param);
+    EXPECT_EQ(base::string16(), load_state.param);
 
     r.Start();
     base::RunLoop().Run();
@@ -4214,6 +4343,11 @@ TEST_F(URLRequestTestHTTP, NetworkDelegateInfoAuth) {
     ASSERT_LT(log_position, entries.size());
     EXPECT_EQ(NetLog::TYPE_URL_REQUEST_DELEGATE, entries[log_position].type);
     EXPECT_EQ(NetLog::PHASE_END, entries[log_position].phase);
+
+    if (i == 1) {
+      log_position = AsyncDelegateLogger::ExpectBeforeNetworkEvents(
+          entries, log_position + 1);
+    }
   }
 
   EXPECT_FALSE(LogContainsEntryWithTypeAfter(
@@ -4235,7 +4369,7 @@ TEST_F(URLRequestTestHTTP, URLRequestDelegateInfo) {
     // A chunked response with delays between chunks is used to make sure that
     // attempts by the URLRequest delegate to log information while reading the
     // body are ignored.  Since they are ignored, this test is robust against
-    // the possability of multiple reads being combined in the unlikely event
+    // the possibility of multiple reads being combined in the unlikely event
     // that it occurs.
     URLRequest r(test_server_.GetURL("chunked?waitBetweenChunks=20"),
                  DEFAULT_PRIORITY,
@@ -4252,14 +4386,18 @@ TEST_F(URLRequestTestHTTP, URLRequestDelegateInfo) {
   CapturingNetLog::CapturedEntryList entries;
   net_log_.GetEntries(&entries);
 
+  size_t log_position = 0;
+
+  log_position = AsyncDelegateLogger::ExpectBeforeNetworkEvents(
+      entries, log_position);
+
   // The delegate info should only have been logged on header complete.  Other
   // times it should silently be ignored.
-
-  size_t log_position = ExpectLogContainsSomewhereAfter(
-          entries,
-          0,
-          NetLog::TYPE_URL_REQUEST_DELEGATE,
-          NetLog::PHASE_BEGIN);
+  log_position =
+      ExpectLogContainsSomewhereAfter(entries,
+                                      log_position + 1,
+                                      NetLog::TYPE_URL_REQUEST_DELEGATE,
+                                      NetLog::PHASE_BEGIN);
 
   log_position = AsyncDelegateLogger::CheckDelegateInfo(entries,
                                                         log_position + 1);
@@ -4306,6 +4444,11 @@ TEST_F(URLRequestTestHTTP, URLRequestDelegateInfoOnRedirect) {
   // OnResponseStarted.
   size_t log_position = 0;
   for (int i = 0; i < 2; ++i) {
+    if (i == 0) {
+      log_position = AsyncDelegateLogger::ExpectBeforeNetworkEvents(
+                         entries, log_position) + 1;
+    }
+
     log_position = ExpectLogContainsSomewhereAfter(
             entries,
             log_position,
@@ -4366,6 +4509,11 @@ TEST_F(URLRequestTestHTTP, URLRequestDelegateOnRedirectCancelled) {
     // still currently supported in that call.
     size_t log_position = 0;
     for (int i = 0; i < 2; ++i) {
+      if (i == 0) {
+        log_position = AsyncDelegateLogger::ExpectBeforeNetworkEvents(
+                           entries, log_position) + 1;
+      }
+
       log_position = ExpectLogContainsSomewhereAfter(
               entries,
               log_position,
@@ -4639,7 +4787,7 @@ TEST_F(URLRequestTestHTTP, PostFileTest) {
 
     base::FilePath dir;
     PathService::Get(base::DIR_EXE, &dir);
-    file_util::SetCurrentDirectory(dir);
+    base::SetCurrentDirectory(dir);
 
     ScopedVector<UploadElementReader> element_readers;
 
@@ -4655,15 +4803,6 @@ TEST_F(URLRequestTestHTTP, PostFileTest) {
                                     0,
                                     kuint64max,
                                     base::Time()));
-
-    // This file should just be ignored in the upload stream.
-    element_readers.push_back(new UploadFileElementReader(
-        base::MessageLoopProxy::current().get(),
-        base::FilePath(FILE_PATH_LITERAL(
-            "c:\\path\\to\\non\\existant\\file.randomness.12345")),
-        0,
-        kuint64max,
-        base::Time()));
     r.set_upload(make_scoped_ptr(
         new UploadDataStream(element_readers.Pass(), 0)));
 
@@ -4673,10 +4812,10 @@ TEST_F(URLRequestTestHTTP, PostFileTest) {
     base::RunLoop().Run();
 
     int64 size = 0;
-    ASSERT_EQ(true, file_util::GetFileSize(path, &size));
+    ASSERT_EQ(true, base::GetFileSize(path, &size));
     scoped_ptr<char[]> buf(new char[size]);
 
-    ASSERT_EQ(size, file_util::ReadFile(path, buf.get(), size));
+    ASSERT_EQ(size, base::ReadFile(path, buf.get(), size));
 
     ASSERT_EQ(1, d.response_started_count())
         << "request failed: " << r.status().status()
@@ -4689,6 +4828,40 @@ TEST_F(URLRequestTestHTTP, PostFileTest) {
   }
 }
 
+TEST_F(URLRequestTestHTTP, PostUnreadableFileTest) {
+  ASSERT_TRUE(test_server_.Start());
+
+  TestDelegate d;
+  {
+    URLRequest r(test_server_.GetURL("echo"), DEFAULT_PRIORITY,
+                 &d, &default_context_);
+    r.set_method("POST");
+
+    ScopedVector<UploadElementReader> element_readers;
+
+    element_readers.push_back(new UploadFileElementReader(
+        base::MessageLoopProxy::current().get(),
+        base::FilePath(FILE_PATH_LITERAL(
+            "c:\\path\\to\\non\\existant\\file.randomness.12345")),
+        0,
+        kuint64max,
+        base::Time()));
+    r.set_upload(make_scoped_ptr(
+        new UploadDataStream(element_readers.Pass(), 0)));
+
+    r.Start();
+    EXPECT_TRUE(r.is_pending());
+
+    base::RunLoop().Run();
+
+    EXPECT_TRUE(d.request_failed());
+    EXPECT_FALSE(d.received_data_before_response());
+    EXPECT_EQ(0, d.bytes_received());
+    EXPECT_EQ(URLRequestStatus::FAILED, r.status().status());
+    EXPECT_EQ(ERR_FILE_NOT_FOUND, r.status().error());
+  }
+}
+
 TEST_F(URLRequestTestHTTP, TestPostChunkedDataBeforeStart) {
   ASSERT_TRUE(test_server_.Start());
 
@@ -4795,14 +4968,13 @@ TEST_F(URLRequestTestHTTP, ProcessSTS) {
 
   TransportSecurityState* security_state =
       default_context_.transport_security_state();
-  bool sni_available = true;
   TransportSecurityState::DomainState domain_state;
-  EXPECT_TRUE(security_state->GetDomainState(
-      SpawnedTestServer::kLocalhost, sni_available, &domain_state));
+  EXPECT_TRUE(security_state->GetDynamicDomainState(
+      SpawnedTestServer::kLocalhost, &domain_state));
   EXPECT_EQ(TransportSecurityState::DomainState::MODE_FORCE_HTTPS,
-            domain_state.upgrade_mode);
-  EXPECT_TRUE(domain_state.sts_include_subdomains);
-  EXPECT_FALSE(domain_state.pkp_include_subdomains);
+            domain_state.sts.upgrade_mode);
+  EXPECT_TRUE(domain_state.sts.include_subdomains);
+  EXPECT_FALSE(domain_state.pkp.include_subdomains);
 #if defined(OS_ANDROID)
   // Android's CertVerifyProc does not (yet) handle pins.
 #else
@@ -4839,17 +5011,15 @@ TEST_F(URLRequestTestHTTP, MAYBE_ProcessPKP) {
 
   TransportSecurityState* security_state =
       default_context_.transport_security_state();
-  bool sni_available = true;
   TransportSecurityState::DomainState domain_state;
-  EXPECT_TRUE(security_state->GetDomainState(
-      SpawnedTestServer::kLocalhost, sni_available, &domain_state));
+  EXPECT_TRUE(security_state->GetDynamicDomainState(
+      SpawnedTestServer::kLocalhost, &domain_state));
   EXPECT_EQ(TransportSecurityState::DomainState::MODE_DEFAULT,
-            domain_state.upgrade_mode);
-  EXPECT_FALSE(domain_state.sts_include_subdomains);
-  EXPECT_FALSE(domain_state.pkp_include_subdomains);
+            domain_state.sts.upgrade_mode);
+  EXPECT_FALSE(domain_state.sts.include_subdomains);
+  EXPECT_FALSE(domain_state.pkp.include_subdomains);
   EXPECT_TRUE(domain_state.HasPublicKeyPins());
-  EXPECT_NE(domain_state.upgrade_expiry,
-            domain_state.dynamic_spki_hashes_expiry);
+  EXPECT_NE(domain_state.sts.expiry, domain_state.pkp.expiry);
 }
 
 TEST_F(URLRequestTestHTTP, ProcessSTSOnce) {
@@ -4872,14 +5042,13 @@ TEST_F(URLRequestTestHTTP, ProcessSTSOnce) {
   // We should have set parameters from the first header, not the second.
   TransportSecurityState* security_state =
       default_context_.transport_security_state();
-  bool sni_available = true;
   TransportSecurityState::DomainState domain_state;
-  EXPECT_TRUE(security_state->GetDomainState(
-      SpawnedTestServer::kLocalhost, sni_available, &domain_state));
+  EXPECT_TRUE(security_state->GetDynamicDomainState(
+      SpawnedTestServer::kLocalhost, &domain_state));
   EXPECT_EQ(TransportSecurityState::DomainState::MODE_FORCE_HTTPS,
-            domain_state.upgrade_mode);
-  EXPECT_FALSE(domain_state.sts_include_subdomains);
-  EXPECT_FALSE(domain_state.pkp_include_subdomains);
+            domain_state.sts.upgrade_mode);
+  EXPECT_FALSE(domain_state.sts.include_subdomains);
+  EXPECT_FALSE(domain_state.pkp.include_subdomains);
 }
 
 TEST_F(URLRequestTestHTTP, ProcessSTSAndPKP) {
@@ -4902,25 +5071,23 @@ TEST_F(URLRequestTestHTTP, ProcessSTSAndPKP) {
   // We should have set parameters from the first header, not the second.
   TransportSecurityState* security_state =
       default_context_.transport_security_state();
-  bool sni_available = true;
   TransportSecurityState::DomainState domain_state;
-  EXPECT_TRUE(security_state->GetDomainState(
-      SpawnedTestServer::kLocalhost, sni_available, &domain_state));
+  EXPECT_TRUE(security_state->GetDynamicDomainState(
+      SpawnedTestServer::kLocalhost, &domain_state));
   EXPECT_EQ(TransportSecurityState::DomainState::MODE_FORCE_HTTPS,
-            domain_state.upgrade_mode);
+            domain_state.sts.upgrade_mode);
 #if defined(OS_ANDROID)
   // Android's CertVerifyProc does not (yet) handle pins.
 #else
   EXPECT_TRUE(domain_state.HasPublicKeyPins());
 #endif
-  EXPECT_NE(domain_state.upgrade_expiry,
-            domain_state.dynamic_spki_hashes_expiry);
+  EXPECT_NE(domain_state.sts.expiry, domain_state.pkp.expiry);
 
   // Even though there is an HSTS header asserting includeSubdomains, it is
   // the *second* such header, and we MUST process only the first.
-  EXPECT_FALSE(domain_state.sts_include_subdomains);
+  EXPECT_FALSE(domain_state.sts.include_subdomains);
   // includeSubdomains does not occur in the test HPKP header.
-  EXPECT_FALSE(domain_state.pkp_include_subdomains);
+  EXPECT_FALSE(domain_state.pkp.include_subdomains);
 }
 
 // Tests that when multiple HPKP headers are present, asserting different
@@ -4944,22 +5111,20 @@ TEST_F(URLRequestTestHTTP, ProcessSTSAndPKP2) {
 
   TransportSecurityState* security_state =
       default_context_.transport_security_state();
-  bool sni_available = true;
   TransportSecurityState::DomainState domain_state;
-  EXPECT_TRUE(security_state->GetDomainState(
-      SpawnedTestServer::kLocalhost, sni_available, &domain_state));
+  EXPECT_TRUE(security_state->GetDynamicDomainState(
+      SpawnedTestServer::kLocalhost, &domain_state));
   EXPECT_EQ(TransportSecurityState::DomainState::MODE_FORCE_HTTPS,
-            domain_state.upgrade_mode);
+            domain_state.sts.upgrade_mode);
 #if defined(OS_ANDROID)
   // Android's CertVerifyProc does not (yet) handle pins.
 #else
   EXPECT_TRUE(domain_state.HasPublicKeyPins());
 #endif
-  EXPECT_NE(domain_state.upgrade_expiry,
-            domain_state.dynamic_spki_hashes_expiry);
+  EXPECT_NE(domain_state.sts.expiry, domain_state.pkp.expiry);
 
-  EXPECT_TRUE(domain_state.sts_include_subdomains);
-  EXPECT_FALSE(domain_state.pkp_include_subdomains);
+  EXPECT_TRUE(domain_state.sts.include_subdomains);
+  EXPECT_FALSE(domain_state.pkp.include_subdomains);
 }
 
 TEST_F(URLRequestTestHTTP, ContentTypeNormalizationTest) {
@@ -4983,20 +5148,27 @@ TEST_F(URLRequestTestHTTP, ContentTypeNormalizationTest) {
   req.Cancel();
 }
 
-TEST_F(URLRequestTestHTTP, ProtocolHandlerAndFactoryRestrictRedirects) {
+TEST_F(URLRequestTestHTTP, ProtocolHandlerAndFactoryRestrictDataRedirects) {
   // Test URLRequestJobFactory::ProtocolHandler::IsSafeRedirectTarget().
-  GURL file_url("file:///foo.txt");
   GURL data_url("data:,foo");
-  FileProtocolHandler file_protocol_handler(base::MessageLoopProxy::current());
-  EXPECT_FALSE(file_protocol_handler.IsSafeRedirectTarget(file_url));
   DataProtocolHandler data_protocol_handler;
   EXPECT_FALSE(data_protocol_handler.IsSafeRedirectTarget(data_url));
 
   // Test URLRequestJobFactoryImpl::IsSafeRedirectTarget().
-  EXPECT_FALSE(job_factory_.IsSafeRedirectTarget(file_url));
   EXPECT_FALSE(job_factory_.IsSafeRedirectTarget(data_url));
 }
 
+#if !defined(DISABLE_FILE_SUPPORT)
+TEST_F(URLRequestTestHTTP, ProtocolHandlerAndFactoryRestrictFileRedirects) {
+  // Test URLRequestJobFactory::ProtocolHandler::IsSafeRedirectTarget().
+  GURL file_url("file:///foo.txt");
+  FileProtocolHandler file_protocol_handler(base::MessageLoopProxy::current());
+  EXPECT_FALSE(file_protocol_handler.IsSafeRedirectTarget(file_url));
+
+  // Test URLRequestJobFactoryImpl::IsSafeRedirectTarget().
+  EXPECT_FALSE(job_factory_.IsSafeRedirectTarget(file_url));
+}
+
 TEST_F(URLRequestTestHTTP, RestrictFileRedirects) {
   ASSERT_TRUE(test_server_.Start());
 
@@ -5011,6 +5183,7 @@ TEST_F(URLRequestTestHTTP, RestrictFileRedirects) {
   EXPECT_EQ(URLRequestStatus::FAILED, req.status().status());
   EXPECT_EQ(ERR_UNSAFE_REDIRECT, req.status().error());
 }
+#endif  // !defined(DISABLE_FILE_SUPPORT)
 
 TEST_F(URLRequestTestHTTP, RestrictDataRedirects) {
   ASSERT_TRUE(test_server_.Start());
@@ -5042,52 +5215,373 @@ TEST_F(URLRequestTestHTTP, RedirectToInvalidURL) {
   EXPECT_EQ(ERR_INVALID_URL, req.status().error());
 }
 
-TEST_F(URLRequestTestHTTP, NoUserPassInReferrer) {
+// Make sure redirects are cached, despite not reading their bodies.
+TEST_F(URLRequestTestHTTP, CacheRedirect) {
   ASSERT_TRUE(test_server_.Start());
+  GURL redirect_url =
+      test_server_.GetURL("files/redirect302-to-echo-cacheable");
 
-  TestDelegate d;
-  URLRequest req(test_server_.GetURL("echoheader?Referer"),
-                 DEFAULT_PRIORITY,
-                 &d,
-                 &default_context_);
-  req.SetReferrer("http://user:pass@foo.com/");
-  req.Start();
-  base::RunLoop().Run();
+  {
+    TestDelegate d;
+    URLRequest req(redirect_url, DEFAULT_PRIORITY, &d, &default_context_);
+    req.Start();
+    base::RunLoop().Run();
+    EXPECT_EQ(URLRequestStatus::SUCCESS, req.status().status());
+    EXPECT_EQ(1, d.received_redirect_count());
+    EXPECT_EQ(test_server_.GetURL("echo"), req.url());
+  }
 
-  EXPECT_EQ(std::string("http://foo.com/"), d.data_received());
+  {
+    TestDelegate d;
+    d.set_quit_on_redirect(true);
+    URLRequest req(redirect_url, DEFAULT_PRIORITY, &d, &default_context_);
+    req.Start();
+    base::RunLoop().Run();
+
+    EXPECT_EQ(1, d.received_redirect_count());
+    EXPECT_EQ(0, d.response_started_count());
+    EXPECT_TRUE(req.was_cached());
+
+    req.FollowDeferredRedirect();
+    base::RunLoop().Run();
+    EXPECT_EQ(1, d.received_redirect_count());
+    EXPECT_EQ(1, d.response_started_count());
+    EXPECT_EQ(URLRequestStatus::SUCCESS, req.status().status());
+    EXPECT_EQ(test_server_.GetURL("echo"), req.url());
+  }
 }
 
-TEST_F(URLRequestTestHTTP, NoFragmentInReferrer) {
+// Make sure a request isn't cached when a NetworkDelegate forces a redirect
+// when the headers are read, since the body won't have been read.
+TEST_F(URLRequestTestHTTP, NoCacheOnNetworkDelegateRedirect) {
   ASSERT_TRUE(test_server_.Start());
+  // URL that is normally cached.
+  GURL initial_url = test_server_.GetURL("cachetime");
 
-  TestDelegate d;
-  URLRequest req(test_server_.GetURL("echoheader?Referer"),
-                 DEFAULT_PRIORITY,
-                 &d,
-                 &default_context_);
-  req.SetReferrer("http://foo.com/test#fragment");
-  req.Start();
-  base::RunLoop().Run();
+  {
+    // Set up the TestNetworkDelegate tp force a redirect.
+    GURL redirect_to_url = test_server_.GetURL("echo");
+    default_network_delegate_.set_redirect_on_headers_received_url(
+        redirect_to_url);
 
-  EXPECT_EQ(std::string("http://foo.com/test"), d.data_received());
+    TestDelegate d;
+    URLRequest req(initial_url, DEFAULT_PRIORITY, &d, &default_context_);
+    req.Start();
+    base::RunLoop().Run();
+    EXPECT_EQ(URLRequestStatus::SUCCESS, req.status().status());
+    EXPECT_EQ(1, d.received_redirect_count());
+    EXPECT_EQ(redirect_to_url, req.url());
+  }
+
+  {
+    TestDelegate d;
+    URLRequest req(initial_url, DEFAULT_PRIORITY, &d, &default_context_);
+    req.Start();
+    base::RunLoop().Run();
+
+    EXPECT_EQ(URLRequestStatus::SUCCESS, req.status().status());
+    EXPECT_FALSE(req.was_cached());
+    EXPECT_EQ(0, d.received_redirect_count());
+    EXPECT_EQ(initial_url, req.url());
+  }
 }
 
-TEST_F(URLRequestTestHTTP, EmptyReferrerAfterValidReferrer) {
+// 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 req(test_server_.GetURL("echoheader?Referer"),
+  {
+    URLRequest r(test_server_.GetURL("whatever"),
                  DEFAULT_PRIORITY,
                  &d,
                  &default_context_);
-  req.SetReferrer("http://foo.com/test#fragment");
-  req.SetReferrer("");
+
+    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 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, RedirectWithReferenceFragmentAndUnrelatedUnsafeUrl) {
+  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());
+  }
+}
+
+// When a delegate has specified a safe redirect URL, assume that the redirect
+// URL should not be changed. In particular, the reference fragment should not
+// be modified.
+TEST_F(URLRequestTestHTTP, RedirectWithReferenceFragment) {
+  ASSERT_TRUE(test_server_.Start());
+
+  GURL original_url(test_server_.GetURL("original#should-not-be-appended"));
+  GURL redirect_url("data:text/html,expect-no-reference-fragment");
+
+  default_network_delegate_.set_redirect_on_headers_received_url(redirect_url);
+  default_network_delegate_.set_allowed_unsafe_redirect_url(redirect_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(redirect_url, r.url());
+  }
+}
+
+// When a URLRequestRedirectJob is created, the redirection must be followed and
+// the reference fragment of the target URL must not be modified.
+TEST_F(URLRequestTestHTTP, RedirectJobWithReferenceFragment) {
+  ASSERT_TRUE(test_server_.Start());
+
+  GURL original_url(test_server_.GetURL("original#should-not-be-appended"));
+  GURL redirect_url(test_server_.GetURL("echo"));
+
+  TestDelegate d;
+  URLRequest r(original_url, DEFAULT_PRIORITY, &d, &default_context_);
+
+  URLRequestRedirectJob* job = new URLRequestRedirectJob(
+      &r, &default_network_delegate_, redirect_url,
+      URLRequestRedirectJob::REDIRECT_302_FOUND, "Very Good Reason");
+  AddTestInterceptor()->set_main_intercept_job(job);
+
+  r.Start();
+  base::RunLoop().Run();
+
+  EXPECT_EQ(URLRequestStatus::SUCCESS, r.status().status());
+  EXPECT_EQ(net::OK, r.status().error());
+  EXPECT_EQ(original_url, r.original_url());
+  EXPECT_EQ(redirect_url, r.url());
+}
+
+TEST_F(URLRequestTestHTTP, NoUserPassInReferrer) {
+  ASSERT_TRUE(test_server_.Start());
+
+  TestDelegate d;
+  URLRequest req(test_server_.GetURL("echoheader?Referer"),
+                 DEFAULT_PRIORITY,
+                 &d,
+                 &default_context_);
+  req.SetReferrer("http://user:pass@foo.com/");
+  req.Start();
+  base::RunLoop().Run();
+
+  EXPECT_EQ(std::string("http://foo.com/"), d.data_received());
+}
+
+TEST_F(URLRequestTestHTTP, NoFragmentInReferrer) {
+  ASSERT_TRUE(test_server_.Start());
+
+  TestDelegate d;
+  URLRequest req(test_server_.GetURL("echoheader?Referer"),
+                 DEFAULT_PRIORITY,
+                 &d,
+                 &default_context_);
+  req.SetReferrer("http://foo.com/test#fragment");
+  req.Start();
+  base::RunLoop().Run();
+
+  EXPECT_EQ(std::string("http://foo.com/test"), d.data_received());
+}
+
+TEST_F(URLRequestTestHTTP, EmptyReferrerAfterValidReferrer) {
+  ASSERT_TRUE(test_server_.Start());
+
+  TestDelegate d;
+  URLRequest req(test_server_.GetURL("echoheader?Referer"),
+                 DEFAULT_PRIORITY,
+                 &d,
+                 &default_context_);
+  req.SetReferrer("http://foo.com/test#fragment");
+  req.SetReferrer("");
   req.Start();
   base::RunLoop().Run();
 
   EXPECT_EQ(std::string("None"), d.data_received());
 }
 
+// Defer network start and then resume, checking that the request was a success
+// and bytes were received.
+TEST_F(URLRequestTestHTTP, DeferredBeforeNetworkStart) {
+  ASSERT_TRUE(test_server_.Start());
+
+  TestDelegate d;
+  {
+    d.set_quit_on_network_start(true);
+    GURL test_url(test_server_.GetURL("echo"));
+    URLRequest req(test_url, DEFAULT_PRIORITY, &d, &default_context_);
+
+    req.Start();
+    base::RunLoop().Run();
+
+    EXPECT_EQ(1, d.received_before_network_start_count());
+    EXPECT_EQ(0, d.response_started_count());
+
+    req.ResumeNetworkStart();
+    base::RunLoop().Run();
+
+    EXPECT_EQ(1, d.response_started_count());
+    EXPECT_NE(0, d.bytes_received());
+    EXPECT_EQ(URLRequestStatus::SUCCESS, req.status().status());
+  }
+}
+
+// Check that OnBeforeNetworkStart is only called once even if there is a
+// redirect.
+TEST_F(URLRequestTestHTTP, BeforeNetworkStartCalledOnce) {
+  ASSERT_TRUE(test_server_.Start());
+
+  TestDelegate d;
+  {
+    d.set_quit_on_redirect(true);
+    d.set_quit_on_network_start(true);
+    URLRequest req(test_server_.GetURL("server-redirect?echo"),
+                   DEFAULT_PRIORITY,
+                   &d,
+                   &default_context_);
+
+    req.Start();
+    base::RunLoop().Run();
+
+    EXPECT_EQ(1, d.received_before_network_start_count());
+    EXPECT_EQ(0, d.response_started_count());
+    EXPECT_EQ(0, d.received_redirect_count());
+
+    req.ResumeNetworkStart();
+    base::RunLoop().Run();
+
+    EXPECT_EQ(1, d.received_redirect_count());
+    req.FollowDeferredRedirect();
+    base::RunLoop().Run();
+
+    // Check that the redirect's new network transaction does not get propagated
+    // to a second OnBeforeNetworkStart() notification.
+    EXPECT_EQ(1, d.received_before_network_start_count());
+
+    EXPECT_EQ(1, d.response_started_count());
+    EXPECT_NE(0, d.bytes_received());
+    EXPECT_EQ(URLRequestStatus::SUCCESS, req.status().status());
+  }
+}
+
+// Cancel the request after learning that the request would use the network.
+TEST_F(URLRequestTestHTTP, CancelOnBeforeNetworkStart) {
+  ASSERT_TRUE(test_server_.Start());
+
+  TestDelegate d;
+  {
+    d.set_quit_on_network_start(true);
+    GURL test_url(test_server_.GetURL("echo"));
+    URLRequest req(test_url, DEFAULT_PRIORITY, &d, &default_context_);
+
+    req.Start();
+    base::RunLoop().Run();
+
+    EXPECT_EQ(1, d.received_before_network_start_count());
+    EXPECT_EQ(0, d.response_started_count());
+
+    req.Cancel();
+    base::RunLoop().Run();
+
+    EXPECT_EQ(1, d.response_started_count());
+    EXPECT_EQ(0, d.bytes_received());
+    EXPECT_EQ(URLRequestStatus::CANCELED, req.status().status());
+  }
+}
+
 TEST_F(URLRequestTestHTTP, CancelRedirect) {
   ASSERT_TRUE(test_server_.Start());
 
@@ -5301,7 +5795,7 @@ TEST_F(URLRequestTestHTTP, BasicAuth) {
                  DEFAULT_PRIORITY,
                  &d,
                  &default_context_);
-    r.set_load_flags(LOAD_VALIDATE_CACHE);
+    r.SetLoadFlags(LOAD_VALIDATE_CACHE);
     r.Start();
 
     base::RunLoop().Run();
@@ -5421,7 +5915,7 @@ TEST_F(URLRequestTestHTTP, BasicAuthLoadTiming) {
                  DEFAULT_PRIORITY,
                  &d,
                  &default_context_);
-    r.set_load_flags(LOAD_VALIDATE_CACHE);
+    r.SetLoadFlags(LOAD_VALIDATE_CACHE);
     r.Start();
 
     base::RunLoop().Run();
@@ -5532,6 +6026,57 @@ TEST_F(URLRequestTestHTTP, Redirect307Tests) {
   HTTPRedirectMethodTest(url, "HEAD", "HEAD", false);
 }
 
+TEST_F(URLRequestTestHTTP, Redirect308Tests) {
+  ASSERT_TRUE(test_server_.Start());
+
+  const GURL url = test_server_.GetURL("files/redirect308-to-echo");
+
+  HTTPRedirectMethodTest(url, "POST", "POST", true);
+  HTTPRedirectMethodTest(url, "PUT", "PUT", true);
+  HTTPRedirectMethodTest(url, "HEAD", "HEAD", false);
+}
+
+// Make sure that 308 responses without bodies are not treated as redirects.
+// Certain legacy apis that pre-date the response code expect this behavior
+// (Like Google Drive).
+TEST_F(URLRequestTestHTTP, NoRedirectOn308WithoutLocationHeader) {
+  ASSERT_TRUE(test_server_.Start());
+
+  TestDelegate d;
+  const GURL url = test_server_.GetURL("files/308-without-location-header");
+
+  URLRequest request(url, DEFAULT_PRIORITY, &d, &default_context_);
+
+  request.Start();
+  base::RunLoop().Run();
+  EXPECT_EQ(URLRequestStatus::SUCCESS, request.status().status());
+  EXPECT_EQ(OK, request.status().error());
+  EXPECT_EQ(0, d.received_redirect_count());
+  EXPECT_EQ(308, request.response_headers()->response_code());
+  EXPECT_EQ("This is not a redirect.", d.data_received());
+}
+
+TEST_F(URLRequestTestHTTP, Redirect302PreserveReferenceFragment) {
+  ASSERT_TRUE(test_server_.Start());
+
+  GURL original_url(test_server_.GetURL("files/redirect302-to-echo#fragment"));
+  GURL expected_url(test_server_.GetURL("echo#fragment"));
+
+  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());
+  }
+}
+
 TEST_F(URLRequestTestHTTP, InterceptPost302RedirectGet) {
   ASSERT_TRUE(test_server_.Start());
 
@@ -5551,7 +6096,7 @@ TEST_F(URLRequestTestHTTP, InterceptPost302RedirectGet) {
 
   URLRequestRedirectJob* job = new URLRequestRedirectJob(
       &req, &default_network_delegate_, test_server_.GetURL("echo"),
-      URLRequestRedirectJob::REDIRECT_302_FOUND);
+      URLRequestRedirectJob::REDIRECT_302_FOUND, "Very Good Reason");
   AddTestInterceptor()->set_main_intercept_job(job);
 
   req.Start();
@@ -5578,7 +6123,8 @@ TEST_F(URLRequestTestHTTP, InterceptPost307RedirectPost) {
 
   URLRequestRedirectJob* job = new URLRequestRedirectJob(
       &req, &default_network_delegate_, test_server_.GetURL("echo"),
-      URLRequestRedirectJob::REDIRECT_307_TEMPORARY_REDIRECT);
+      URLRequestRedirectJob::REDIRECT_307_TEMPORARY_REDIRECT,
+      "Very Good Reason");
   AddTestInterceptor()->set_main_intercept_job(job);
 
   req.Start();
@@ -5591,7 +6137,7 @@ TEST_F(URLRequestTestHTTP, InterceptPost307RedirectPost) {
 TEST_F(URLRequestTestHTTP, DefaultAcceptLanguage) {
   ASSERT_TRUE(test_server_.Start());
 
-  StaticHttpUserAgentSettings settings("en", EmptyString());
+  StaticHttpUserAgentSettings settings("en", std::string());
   TestNetworkDelegate network_delegate;  // Must outlive URLRequests.
   TestURLRequestContext context(true);
   context.set_network_delegate(&network_delegate);
@@ -5612,7 +6158,8 @@ TEST_F(URLRequestTestHTTP, DefaultAcceptLanguage) {
 TEST_F(URLRequestTestHTTP, EmptyAcceptLanguage) {
   ASSERT_TRUE(test_server_.Start());
 
-  StaticHttpUserAgentSettings settings(EmptyString(), EmptyString());
+  std::string empty_string;  // Avoid most vexing parse on line below.
+  StaticHttpUserAgentSettings settings(empty_string, empty_string);
   TestNetworkDelegate network_delegate;  // Must outlive URLRequests.
   TestURLRequestContext context(true);
   context.set_network_delegate(&network_delegate);
@@ -5712,7 +6259,8 @@ TEST_F(URLRequestTestHTTP, DefaultUserAgent) {
                  &default_context_);
   req.Start();
   base::RunLoop().Run();
-  EXPECT_EQ(req.context()->GetUserAgent(req.url()), d.data_received());
+  EXPECT_EQ(req.context()->http_user_agent_settings()->GetUserAgent(),
+            d.data_received());
 }
 
 // Check that if request overrides the User-Agent header,
@@ -5730,10 +6278,7 @@ TEST_F(URLRequestTestHTTP, OverrideUserAgent) {
   req.SetExtraRequestHeaders(headers);
   req.Start();
   base::RunLoop().Run();
-  // If the net tests are being run with ChromeFrame then we need to allow for
-  // the 'chromeframe' suffix which is added to the user agent before the
-  // closing parentheses.
-  EXPECT_TRUE(StartsWithASCII(d.data_received(), "Lynx (textmode", true));
+  EXPECT_EQ(std::string("Lynx (textmode)"), d.data_received());
 }
 
 // Check that a NULL HttpUserAgentSettings causes the corresponding empty
@@ -5783,7 +6328,7 @@ TEST_F(URLRequestTestHTTP, SetSubsequentJobPriority) {
   scoped_refptr<URLRequestRedirectJob> redirect_job =
       new URLRequestRedirectJob(
           &req, &default_network_delegate_, test_server_.GetURL("echo"),
-          URLRequestRedirectJob::REDIRECT_302_FOUND);
+          URLRequestRedirectJob::REDIRECT_302_FOUND, "Very Good Reason");
   AddTestInterceptor()->set_main_intercept_job(redirect_job.get());
 
   req.SetPriority(LOW);
@@ -5799,6 +6344,80 @@ TEST_F(URLRequestTestHTTP, SetSubsequentJobPriority) {
   EXPECT_EQ(LOW, job->priority());
 }
 
+// Check that creating a network request while entering/exiting suspend mode
+// fails as it should.  This is the only case where an HttpTransactionFactory
+// does not return an HttpTransaction.
+TEST_F(URLRequestTestHTTP, NetworkSuspendTest) {
+  // Create a new HttpNetworkLayer that thinks it's suspended.
+  HttpNetworkSession::Params params;
+  params.host_resolver = default_context_.host_resolver();
+  params.cert_verifier = default_context_.cert_verifier();
+  params.transport_security_state = default_context_.transport_security_state();
+  params.proxy_service = default_context_.proxy_service();
+  params.ssl_config_service = default_context_.ssl_config_service();
+  params.http_auth_handler_factory =
+      default_context_.http_auth_handler_factory();
+  params.network_delegate = &default_network_delegate_;
+  params.http_server_properties = default_context_.http_server_properties();
+  scoped_ptr<HttpNetworkLayer> network_layer(
+      new HttpNetworkLayer(new HttpNetworkSession(params)));
+  network_layer->OnSuspend();
+
+  HttpCache http_cache(network_layer.release(), default_context_.net_log(),
+                       HttpCache::DefaultBackend::InMemory(0));
+
+  TestURLRequestContext context(true);
+  context.set_http_transaction_factory(&http_cache);
+  context.Init();
+
+  TestDelegate d;
+  URLRequest req(GURL("http://127.0.0.1/"),
+                 DEFAULT_PRIORITY,
+                 &d,
+                 &context);
+  req.Start();
+  base::RunLoop().Run();
+
+  EXPECT_TRUE(d.request_failed());
+  EXPECT_EQ(URLRequestStatus::FAILED, req.status().status());
+  EXPECT_EQ(ERR_NETWORK_IO_SUSPENDED, req.status().error());
+}
+
+// Check that creating a network request while entering/exiting suspend mode
+// fails as it should in the case there is no cache.  This is the only case
+// where an HttpTransactionFactory does not return an HttpTransaction.
+TEST_F(URLRequestTestHTTP, NetworkSuspendTestNoCache) {
+  // Create a new HttpNetworkLayer that thinks it's suspended.
+  HttpNetworkSession::Params params;
+  params.host_resolver = default_context_.host_resolver();
+  params.cert_verifier = default_context_.cert_verifier();
+  params.transport_security_state = default_context_.transport_security_state();
+  params.proxy_service = default_context_.proxy_service();
+  params.ssl_config_service = default_context_.ssl_config_service();
+  params.http_auth_handler_factory =
+      default_context_.http_auth_handler_factory();
+  params.network_delegate = &default_network_delegate_;
+  params.http_server_properties = default_context_.http_server_properties();
+  HttpNetworkLayer network_layer(new HttpNetworkSession(params));
+  network_layer.OnSuspend();
+
+  TestURLRequestContext context(true);
+  context.set_http_transaction_factory(&network_layer);
+  context.Init();
+
+  TestDelegate d;
+  URLRequest req(GURL("http://127.0.0.1/"),
+                 DEFAULT_PRIORITY,
+                 &d,
+                 &context);
+  req.Start();
+  base::RunLoop().Run();
+
+  EXPECT_TRUE(d.request_failed());
+  EXPECT_EQ(URLRequestStatus::FAILED, req.status().status());
+  EXPECT_EQ(ERR_NETWORK_IO_SUSPENDED, req.status().error());
+}
+
 class HTTPSRequestTest : public testing::Test {
  public:
   HTTPSRequestTest() : default_context_(true) {
@@ -5920,12 +6539,11 @@ TEST_F(HTTPSRequestTest, HTTPSExpiredTest) {
 // Tests TLSv1.1 -> TLSv1 fallback. Verifies that we don't fall back more
 // than necessary.
 TEST_F(HTTPSRequestTest, TLSv1Fallback) {
-  uint16 default_version_max = SSLConfigService::default_version_max();
   // The OpenSSL library in use may not support TLS 1.1.
 #if !defined(USE_OPENSSL)
-  EXPECT_GT(default_version_max, SSL_PROTOCOL_VERSION_TLS1);
+  EXPECT_GT(kDefaultSSLVersionMax, SSL_PROTOCOL_VERSION_TLS1);
 #endif
-  if (default_version_max <= SSL_PROTOCOL_VERSION_TLS1)
+  if (kDefaultSSLVersionMax <= SSL_PROTOCOL_VERSION_TLS1)
     return;
 
   SpawnedTestServer::SSLOptions ssl_options(
@@ -5955,6 +6573,46 @@ TEST_F(HTTPSRequestTest, TLSv1Fallback) {
   EXPECT_TRUE(r.ssl_info().connection_status & SSL_CONNECTION_VERSION_FALLBACK);
 }
 
+// Tests that we don't fallback with servers that implement TLS_FALLBACK_SCSV.
+#if defined(USE_OPENSSL)
+TEST_F(HTTPSRequestTest, DISABLED_FallbackSCSV) {
+#else
+TEST_F(HTTPSRequestTest, FallbackSCSV) {
+#endif
+  SpawnedTestServer::SSLOptions ssl_options(
+      SpawnedTestServer::SSLOptions::CERT_OK);
+  // Configure HTTPS server to be intolerant of TLS >= 1.0 in order to trigger
+  // a version fallback.
+  ssl_options.tls_intolerant =
+      SpawnedTestServer::SSLOptions::TLS_INTOLERANT_ALL;
+  // Have the server process TLS_FALLBACK_SCSV so that version fallback
+  // connections are rejected.
+  ssl_options.fallback_scsv_enabled = true;
+
+  SpawnedTestServer test_server(
+      SpawnedTestServer::TYPE_HTTPS,
+      ssl_options,
+      base::FilePath(FILE_PATH_LITERAL("net/data/ssl")));
+  ASSERT_TRUE(test_server.Start());
+
+  TestDelegate d;
+  TestURLRequestContext context(true);
+  context.Init();
+  d.set_allow_certificate_errors(true);
+  URLRequest r(
+      test_server.GetURL(std::string()), DEFAULT_PRIORITY, &d, &context);
+  r.Start();
+
+  base::RunLoop().Run();
+
+  EXPECT_EQ(1, d.response_started_count());
+  // ERR_SSL_VERSION_OR_CIPHER_MISMATCH is how the server simulates version
+  // intolerance. If the fallback SCSV is processed when the original error
+  // that caused the fallback should be returned, which should be
+  // ERR_SSL_VERSION_OR_CIPHER_MISMATCH.
+  EXPECT_EQ(ERR_SSL_VERSION_OR_CIPHER_MISMATCH, r.status().error());
+}
+
 // This tests that a load of www.google.com with a certificate error sets
 // the |certificate_errors_are_fatal| flag correctly. This flag will cause
 // the interstitial to be fatal.
@@ -6012,11 +6670,10 @@ TEST_F(HTTPSRequestTest, HTTPSErrorsNoClobberTSSTest) {
       base::FilePath(FILE_PATH_LITERAL("net/data/ssl")));
   ASSERT_TRUE(test_server.Start());
 
-  // We require that the URL be www.google.com in order to pick up the
-  // preloaded and dynamic HSTS and public key pin entries in the
-  // TransportSecurityState. This means that we have to use a
-  // MockHostResolver in order to direct www.google.com to the testserver.
-  // By default, MockHostResolver maps all hosts to 127.0.0.1.
+  // We require that the URL be www.google.com in order to pick up the static
+  // and dynamic STS and PKP entries in the TransportSecurityState. This means
+  // that we have to use a MockHostResolver in order to direct www.google.com to
+  // the testserver. By default, MockHostResolver maps all hosts to 127.0.0.1.
 
   MockHostResolver host_resolver;
   TestNetworkDelegate network_delegate;  // Must outlive URLRequest.
@@ -6024,12 +6681,17 @@ TEST_F(HTTPSRequestTest, HTTPSErrorsNoClobberTSSTest) {
   context.set_network_delegate(&network_delegate);
   context.set_host_resolver(&host_resolver);
   TransportSecurityState transport_security_state;
-  TransportSecurityState::DomainState domain_state;
-  EXPECT_TRUE(transport_security_state.GetDomainState("www.google.com", true,
-                                                      &domain_state));
+
+  TransportSecurityState::DomainState static_domain_state;
+  EXPECT_TRUE(transport_security_state.GetStaticDomainState(
+      "www.google.com", true, &static_domain_state));
   context.set_transport_security_state(&transport_security_state);
   context.Init();
 
+  TransportSecurityState::DomainState dynamic_domain_state;
+  EXPECT_FALSE(transport_security_state.GetDynamicDomainState(
+      "www.google.com", &dynamic_domain_state));
+
   TestDelegate d;
   URLRequest r(GURL(base::StringPrintf("https://www.google.com:%d",
                                        test_server.host_port_pair().port())),
@@ -6047,21 +6709,24 @@ TEST_F(HTTPSRequestTest, HTTPSErrorsNoClobberTSSTest) {
   EXPECT_TRUE(d.have_certificate_errors());
   EXPECT_TRUE(d.certificate_errors_are_fatal());
 
-  // Get a fresh copy of the state, and check that it hasn't been updated.
-  TransportSecurityState::DomainState new_domain_state;
-  EXPECT_TRUE(transport_security_state.GetDomainState("www.google.com", true,
-                                                      &new_domain_state));
-  EXPECT_EQ(new_domain_state.upgrade_mode, domain_state.upgrade_mode);
-  EXPECT_EQ(new_domain_state.sts_include_subdomains,
-            domain_state.sts_include_subdomains);
-  EXPECT_EQ(new_domain_state.pkp_include_subdomains,
-            domain_state.pkp_include_subdomains);
-  EXPECT_TRUE(FingerprintsEqual(new_domain_state.static_spki_hashes,
-                                domain_state.static_spki_hashes));
-  EXPECT_TRUE(FingerprintsEqual(new_domain_state.dynamic_spki_hashes,
-                                domain_state.dynamic_spki_hashes));
-  EXPECT_TRUE(FingerprintsEqual(new_domain_state.bad_static_spki_hashes,
-                                domain_state.bad_static_spki_hashes));
+  // Get a fresh copy of the states, and check that they haven't changed.
+  TransportSecurityState::DomainState new_static_domain_state;
+  EXPECT_TRUE(transport_security_state.GetStaticDomainState(
+      "www.google.com", true, &new_static_domain_state));
+  TransportSecurityState::DomainState new_dynamic_domain_state;
+  EXPECT_FALSE(transport_security_state.GetDynamicDomainState(
+      "www.google.com", &new_dynamic_domain_state));
+
+  EXPECT_EQ(new_static_domain_state.sts.upgrade_mode,
+            static_domain_state.sts.upgrade_mode);
+  EXPECT_EQ(new_static_domain_state.sts.include_subdomains,
+            static_domain_state.sts.include_subdomains);
+  EXPECT_EQ(new_static_domain_state.pkp.include_subdomains,
+            static_domain_state.pkp.include_subdomains);
+  EXPECT_TRUE(FingerprintsEqual(new_static_domain_state.pkp.spki_hashes,
+                                static_domain_state.pkp.spki_hashes));
+  EXPECT_TRUE(FingerprintsEqual(new_static_domain_state.pkp.bad_spki_hashes,
+                                static_domain_state.pkp.bad_spki_hashes));
 }
 
 // Make sure HSTS preserves a POST request's method and body.
@@ -6375,6 +7040,104 @@ TEST_F(HTTPSRequestTest, SSLSessionCacheShardTest) {
   }
 }
 
+class HTTPSSessionTest : public testing::Test {
+ public:
+  HTTPSSessionTest() : default_context_(true) {
+    cert_verifier_.set_default_result(net::OK);
+
+    default_context_.set_network_delegate(&default_network_delegate_);
+    default_context_.set_cert_verifier(&cert_verifier_);
+    default_context_.Init();
+  }
+  virtual ~HTTPSSessionTest() {}
+
+ protected:
+  MockCertVerifier cert_verifier_;
+  TestNetworkDelegate default_network_delegate_;  // Must outlive URLRequest.
+  TestURLRequestContext default_context_;
+};
+
+// Tests that session resumption is not attempted if an invalid certificate
+// is presented.
+TEST_F(HTTPSSessionTest, DontResumeSessionsForInvalidCertificates) {
+  SpawnedTestServer::SSLOptions ssl_options;
+  ssl_options.record_resume = true;
+  SpawnedTestServer test_server(
+      SpawnedTestServer::TYPE_HTTPS,
+      ssl_options,
+      base::FilePath(FILE_PATH_LITERAL("net/data/ssl")));
+  ASSERT_TRUE(test_server.Start());
+
+  SSLClientSocket::ClearSessionCache();
+
+  // Simulate the certificate being expired and attempt a connection.
+  cert_verifier_.set_default_result(net::ERR_CERT_DATE_INVALID);
+  {
+    TestDelegate d;
+    URLRequest r(test_server.GetURL("ssl-session-cache"),
+                 DEFAULT_PRIORITY,
+                 &d,
+                 &default_context_);
+
+    r.Start();
+    EXPECT_TRUE(r.is_pending());
+
+    base::RunLoop().Run();
+
+    EXPECT_EQ(1, d.response_started_count());
+  }
+
+  reinterpret_cast<HttpCache*>(default_context_.http_transaction_factory())->
+    CloseAllConnections();
+
+  // Now change the certificate to be acceptable (so that the response is
+  // loaded), and ensure that no session id is presented to the peer.
+  cert_verifier_.set_default_result(net::OK);
+  {
+    TestDelegate d;
+    URLRequest r(test_server.GetURL("ssl-session-cache"),
+                 DEFAULT_PRIORITY,
+                 &d,
+                 &default_context_);
+
+    r.Start();
+    EXPECT_TRUE(r.is_pending());
+
+    base::RunLoop().Run();
+
+    // The response will look like;
+    //   insert abc
+    //   insert xyz
+    //
+    // With a newline at the end which makes the split think that there are
+    // three lines.
+    //
+    // If a session was presented (eg: a bug), then the response would look
+    // like;
+    //   insert abc
+    //   lookup abc
+    //   insert xyz
+
+    EXPECT_EQ(1, d.response_started_count());
+    std::vector<std::string> lines;
+    base::SplitString(d.data_received(), '\n', &lines);
+    ASSERT_EQ(3u, lines.size()) << d.data_received();
+
+    std::string session_id;
+    for (size_t i = 0; i < 2; i++) {
+      std::vector<std::string> parts;
+      base::SplitString(lines[i], '\t', &parts);
+      ASSERT_EQ(2u, parts.size());
+      EXPECT_EQ("insert", parts[0]);
+      if (i == 0) {
+        session_id = parts[1];
+      } else {
+        EXPECT_NE(session_id, parts[1]);
+      }
+    }
+  }
+}
+
 class TestSSLConfigService : public SSLConfigService {
  public:
   TestSSLConfigService(bool ev_enabled,
@@ -6522,12 +7285,12 @@ static bool SystemSupportsHardFailRevocationChecking() {
 // several tests are effected because our testing EV certificate won't be
 // recognised as EV.
 static bool SystemUsesChromiumEVMetadata() {
-#if defined(USE_OPENSSL)
+#if defined(USE_OPENSSL_CERTS) && !defined(OS_ANDROID)
   // http://crbug.com/117478 - OpenSSL does not support EV validation.
   return false;
-#elif defined(OS_MACOSX) && !defined(OS_IOS)
-  // On OS X, we use the system to tell us whether a certificate is EV or not
-  // and the system won't recognise our testing root.
+#elif (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_ANDROID)
+  // On OS X and Android, we use the system to tell us whether a certificate is
+  // EV or not and the system won't recognise our testing root.
   return false;
 #else
   return true;
@@ -6970,7 +7733,7 @@ TEST_F(URLRequestTestFTP, DISABLED_FTPGetTestAnonymous) {
     base::RunLoop().Run();
 
     int64 file_size = 0;
-    file_util::GetFileSize(app_path, &file_size);
+    base::GetFileSize(app_path, &file_size);
 
     EXPECT_FALSE(r.is_pending());
     EXPECT_EQ(1, d.response_started_count());
@@ -7003,7 +7766,7 @@ TEST_F(URLRequestTestFTP, DISABLED_FTPGetTest) {
     base::RunLoop().Run();
 
     int64 file_size = 0;
-    file_util::GetFileSize(app_path, &file_size);
+    base::GetFileSize(app_path, &file_size);
 
     EXPECT_FALSE(r.is_pending());
     EXPECT_EQ(test_server_.host_port_pair().host(),
@@ -7040,7 +7803,7 @@ TEST_F(URLRequestTestFTP, DISABLED_FTPCheckWrongPassword) {
     base::RunLoop().Run();
 
     int64 file_size = 0;
-    file_util::GetFileSize(app_path, &file_size);
+    base::GetFileSize(app_path, &file_size);
 
     EXPECT_FALSE(r.is_pending());
     EXPECT_EQ(1, d.response_started_count());
@@ -7072,7 +7835,7 @@ TEST_F(URLRequestTestFTP, DISABLED_FTPCheckWrongPasswordRestart) {
     base::RunLoop().Run();
 
     int64 file_size = 0;
-    file_util::GetFileSize(app_path, &file_size);
+    base::GetFileSize(app_path, &file_size);
 
     EXPECT_FALSE(r.is_pending());
     EXPECT_EQ(1, d.response_started_count());
@@ -7101,7 +7864,7 @@ TEST_F(URLRequestTestFTP, DISABLED_FTPCheckWrongUser) {
     base::RunLoop().Run();
 
     int64 file_size = 0;
-    file_util::GetFileSize(app_path, &file_size);
+    base::GetFileSize(app_path, &file_size);
 
     EXPECT_FALSE(r.is_pending());
     EXPECT_EQ(1, d.response_started_count());
@@ -7133,7 +7896,7 @@ TEST_F(URLRequestTestFTP, DISABLED_FTPCheckWrongUserRestart) {
     base::RunLoop().Run();
 
     int64 file_size = 0;
-    file_util::GetFileSize(app_path, &file_size);
+    base::GetFileSize(app_path, &file_size);
 
     EXPECT_FALSE(r.is_pending());
     EXPECT_EQ(1, d.response_started_count());
@@ -7164,7 +7927,7 @@ TEST_F(URLRequestTestFTP, DISABLED_FTPCacheURLCredentials) {
     base::RunLoop().Run();
 
     int64 file_size = 0;
-    file_util::GetFileSize(app_path, &file_size);
+    base::GetFileSize(app_path, &file_size);
 
     EXPECT_FALSE(r.is_pending());
     EXPECT_EQ(1, d->response_started_count());
@@ -7185,7 +7948,7 @@ TEST_F(URLRequestTestFTP, DISABLED_FTPCacheURLCredentials) {
     base::RunLoop().Run();
 
     int64 file_size = 0;
-    file_util::GetFileSize(app_path, &file_size);
+    base::GetFileSize(app_path, &file_size);
 
     EXPECT_FALSE(r.is_pending());
     EXPECT_EQ(1, d->response_started_count());
@@ -7218,7 +7981,7 @@ TEST_F(URLRequestTestFTP, DISABLED_FTPCacheLoginBoxCredentials) {
     base::RunLoop().Run();
 
     int64 file_size = 0;
-    file_util::GetFileSize(app_path, &file_size);
+    base::GetFileSize(app_path, &file_size);
 
     EXPECT_FALSE(r.is_pending());
     EXPECT_EQ(1, d->response_started_count());
@@ -7242,7 +8005,7 @@ TEST_F(URLRequestTestFTP, DISABLED_FTPCacheLoginBoxCredentials) {
     base::RunLoop().Run();
 
     int64 file_size = 0;
-    file_util::GetFileSize(app_path, &file_size);
+    base::GetFileSize(app_path, &file_size);
 
     EXPECT_FALSE(r.is_pending());
     EXPECT_EQ(1, d->response_started_count());