More net/ method ordering.

BUG=68682
TEST=compiles

Review URL: http://codereview.chromium.org/6339012

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@72710 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/net/base/upload_data.cc b/net/base/upload_data.cc
index f148cac1..1dd8bbce 100644
--- a/net/base/upload_data.cc
+++ b/net/base/upload_data.cc
@@ -28,6 +28,18 @@
   delete file_stream_;
 }
 
+void UploadData::Element::SetToChunk(const char* bytes, int bytes_len) {
+  std::string chunk_length = StringPrintf("%X\r\n", bytes_len);
+  bytes_.clear();
+  bytes_.insert(bytes_.end(), chunk_length.data(),
+                chunk_length.data() + chunk_length.length());
+  bytes_.insert(bytes_.end(), bytes, bytes + bytes_len);
+  const char* crlf = "\r\n";
+  bytes_.insert(bytes_.end(), crlf, crlf + 2);
+  type_ = TYPE_CHUNK;
+  is_last_chunk_ = (bytes_len == 0);
+}
+
 uint64 UploadData::Element::GetContentLength() {
   if (override_content_length_ || content_length_computed_)
     return content_length_;
@@ -67,18 +79,6 @@
   return content_length_;
 }
 
-void UploadData::Element::SetToChunk(const char* bytes, int bytes_len) {
-  std::string chunk_length = StringPrintf("%X\r\n", bytes_len);
-  bytes_.clear();
-  bytes_.insert(bytes_.end(), chunk_length.data(),
-                chunk_length.data() + chunk_length.length());
-  bytes_.insert(bytes_.end(), bytes, bytes + bytes_len);
-  const char* crlf = "\r\n";
-  bytes_.insert(bytes_.end(), crlf, crlf + 2);
-  type_ = TYPE_CHUNK;
-  is_last_chunk_ = (bytes_len == 0);
-}
-
 FileStream* UploadData::Element::NewFileStreamForReading() {
   // In common usage GetContentLength() will call this first and store the
   // result into |file_| and a subsequent call (from UploadDataStream) will
diff --git a/net/base/upload_data_stream.cc b/net/base/upload_data_stream.cc
index 1f77f062..9f7bdbb 100644
--- a/net/base/upload_data_stream.cc
+++ b/net/base/upload_data_stream.cc
@@ -12,6 +12,9 @@
 
 namespace net {
 
+UploadDataStream::~UploadDataStream() {
+}
+
 UploadDataStream* UploadDataStream::Create(UploadData* data, int* error_code) {
   scoped_ptr<UploadDataStream> stream(new UploadDataStream(data));
   int rv = stream->FillBuf();
@@ -50,9 +53,6 @@
       eof_(false) {
 }
 
-UploadDataStream::~UploadDataStream() {
-}
-
 int UploadDataStream::FillBuf() {
   std::vector<UploadData::Element>& elements = *data_->elements();
 
diff --git a/net/base/x509_certificate.cc b/net/base/x509_certificate.cc
index b705790..64695370 100644
--- a/net/base/x509_certificate.cc
+++ b/net/base/x509_certificate.cc
@@ -121,6 +121,19 @@
   return fingerprint_functor(lhs->fingerprint_, rhs->fingerprint_);
 }
 
+X509Certificate::X509Certificate(const std::string& subject,
+                                 const std::string& issuer,
+                                 base::Time start_date,
+                                 base::Time expiration_date)
+    : subject_(subject),
+      issuer_(issuer),
+      valid_start_(start_date),
+      valid_expiry_(expiration_date),
+      cert_handle_(NULL),
+      source_(SOURCE_UNUSED) {
+  memset(fingerprint_.data, 0, sizeof(fingerprint_.data));
+}
+
 // static
 X509Certificate* X509Certificate::CreateFromHandle(
     OSCertHandle cert_handle,
@@ -283,40 +296,6 @@
   return results;
 }
 
-X509Certificate::X509Certificate(OSCertHandle cert_handle,
-                                 Source source,
-                                 const OSCertHandles& intermediates)
-    : cert_handle_(DupOSCertHandle(cert_handle)),
-      source_(source) {
-  // Copy/retain the intermediate cert handles.
-  for (size_t i = 0; i < intermediates.size(); ++i)
-    intermediate_ca_certs_.push_back(DupOSCertHandle(intermediates[i]));
-  // Platform-specific initialization.
-  Initialize();
-}
-
-X509Certificate::X509Certificate(const std::string& subject,
-                                 const std::string& issuer,
-                                 base::Time start_date,
-                                 base::Time expiration_date)
-    : subject_(subject),
-      issuer_(issuer),
-      valid_start_(start_date),
-      valid_expiry_(expiration_date),
-      cert_handle_(NULL),
-      source_(SOURCE_UNUSED) {
-  memset(fingerprint_.data, 0, sizeof(fingerprint_.data));
-}
-
-X509Certificate::~X509Certificate() {
-  // We might not be in the cache, but it is safe to remove ourselves anyway.
-  g_x509_certificate_cache.Get().Remove(this);
-  if (cert_handle_)
-    FreeOSCertHandle(cert_handle_);
-  for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i)
-    FreeOSCertHandle(intermediate_ca_certs_[i]);
-}
-
 bool X509Certificate::HasExpired() const {
   return base::Time::Now() > valid_expiry();
 }
@@ -345,4 +324,25 @@
   return true;
 }
 
+X509Certificate::X509Certificate(OSCertHandle cert_handle,
+                                 Source source,
+                                 const OSCertHandles& intermediates)
+    : cert_handle_(DupOSCertHandle(cert_handle)),
+      source_(source) {
+  // Copy/retain the intermediate cert handles.
+  for (size_t i = 0; i < intermediates.size(); ++i)
+    intermediate_ca_certs_.push_back(DupOSCertHandle(intermediates[i]));
+  // Platform-specific initialization.
+  Initialize();
+}
+
+X509Certificate::~X509Certificate() {
+  // We might not be in the cache, but it is safe to remove ourselves anyway.
+  g_x509_certificate_cache.Get().Remove(this);
+  if (cert_handle_)
+    FreeOSCertHandle(cert_handle_);
+  for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i)
+    FreeOSCertHandle(intermediate_ca_certs_[i]);
+}
+
 }  // namespace net
diff --git a/net/disk_cache/backend_impl.cc b/net/disk_cache/backend_impl.cc
index 89890e9..0a6ad778 100644
--- a/net/disk_cache/backend_impl.cc
+++ b/net/disk_cache/backend_impl.cc
@@ -344,34 +344,6 @@
 
 // ------------------------------------------------------------------------
 
-// If the initialization of the cache fails, and force is true, we will discard
-// the whole cache and create a new one. In order to process a potentially large
-// number of files, we'll rename the cache folder to old_ + original_name +
-// number, (located on the same parent folder), and spawn a worker thread to
-// delete all the files on all the stale cache folders. The whole process can
-// still fail if we are not able to rename the cache folder (for instance due to
-// a sharing violation), and in that case a cache for this profile (on the
-// desired path) cannot be created.
-//
-// Static.
-int BackendImpl::CreateBackend(const FilePath& full_path, bool force,
-                               int max_bytes, net::CacheType type,
-                               uint32 flags, base::MessageLoopProxy* thread,
-                               net::NetLog* net_log, Backend** backend,
-                               CompletionCallback* callback) {
-  DCHECK(callback);
-  CacheCreator* creator = new CacheCreator(full_path, force, max_bytes, type,
-                                           flags, thread, net_log, backend,
-                                           callback);
-  // This object will self-destroy when finished.
-  return creator->Run();
-}
-
-int BackendImpl::Init(CompletionCallback* callback) {
-  background_queue_.Init(callback);
-  return net::ERR_IO_PENDING;
-}
-
 BackendImpl::BackendImpl(const FilePath& path,
                          base::MessageLoopProxy* cache_thread,
                          net::NetLog* net_log)
@@ -436,7 +408,33 @@
   }
 }
 
-// ------------------------------------------------------------------------
+// If the initialization of the cache fails, and force is true, we will discard
+// the whole cache and create a new one. In order to process a potentially large
+// number of files, we'll rename the cache folder to old_ + original_name +
+// number, (located on the same parent folder), and spawn a worker thread to
+// delete all the files on all the stale cache folders. The whole process can
+// still fail if we are not able to rename the cache folder (for instance due to
+// a sharing violation), and in that case a cache for this profile (on the
+// desired path) cannot be created.
+//
+// Static.
+int BackendImpl::CreateBackend(const FilePath& full_path, bool force,
+                               int max_bytes, net::CacheType type,
+                               uint32 flags, base::MessageLoopProxy* thread,
+                               net::NetLog* net_log, Backend** backend,
+                               CompletionCallback* callback) {
+  DCHECK(callback);
+  CacheCreator* creator = new CacheCreator(full_path, force, max_bytes, type,
+                                           flags, thread, net_log, backend,
+                                           callback);
+  // This object will self-destroy when finished.
+  return creator->Run();
+}
+
+int BackendImpl::Init(CompletionCallback* callback) {
+  background_queue_.Init(callback);
+  return net::ERR_IO_PENDING;
+}
 
 int BackendImpl::SyncInit() {
   DCHECK(!init_);
diff --git a/net/disk_cache/file_posix.cc b/net/disk_cache/file_posix.cc
index 01dafd3c..740d108 100644
--- a/net/disk_cache/file_posix.cc
+++ b/net/disk_cache/file_posix.cc
@@ -189,11 +189,6 @@
   return true;
 }
 
-File::~File() {
-  if (platform_file_)
-    close(platform_file_);
-}
-
 base::PlatformFile File::platform_file() const {
   return platform_file_;
 }
@@ -255,19 +250,6 @@
   return AsyncWrite(buffer, buffer_len, offset, callback, completed);
 }
 
-bool File::AsyncWrite(const void* buffer, size_t buffer_len, size_t offset,
-                      FileIOCallback* callback, bool* completed) {
-  DCHECK(init_);
-  if (buffer_len > ULONG_MAX || offset > ULONG_MAX)
-    return false;
-
-  GetFileInFlightIO()->PostWrite(this, buffer, buffer_len, offset, callback);
-
-  if (completed)
-    *completed = false;
-  return true;
-}
-
 bool File::SetLength(size_t length) {
   DCHECK(init_);
   if (length > ULONG_MAX)
@@ -290,4 +272,22 @@
   DeleteFileInFlightIO();
 }
 
+File::~File() {
+  if (platform_file_)
+    close(platform_file_);
+}
+
+bool File::AsyncWrite(const void* buffer, size_t buffer_len, size_t offset,
+                      FileIOCallback* callback, bool* completed) {
+  DCHECK(init_);
+  if (buffer_len > ULONG_MAX || offset > ULONG_MAX)
+    return false;
+
+  GetFileInFlightIO()->PostWrite(this, buffer, buffer_len, offset, callback);
+
+  if (completed)
+    *completed = false;
+  return true;
+}
+
 }  // namespace disk_cache
diff --git a/net/disk_cache/mapped_file_posix.cc b/net/disk_cache/mapped_file_posix.cc
index f9a361b..9abfa5cd 100644
--- a/net/disk_cache/mapped_file_posix.cc
+++ b/net/disk_cache/mapped_file_posix.cc
@@ -32,16 +32,6 @@
   return buffer_;
 }
 
-MappedFile::~MappedFile() {
-  if (!init_)
-    return;
-
-  if (buffer_) {
-    int ret = munmap(buffer_, view_size_);
-    DCHECK(0 == ret);
-  }
-}
-
 bool MappedFile::Load(const FileBlock* block) {
   size_t offset = block->offset() + view_size_;
   return Read(block->buffer(), block->size(), offset);
@@ -52,4 +42,14 @@
   return Write(block->buffer(), block->size(), offset);
 }
 
+MappedFile::~MappedFile() {
+  if (!init_)
+    return;
+
+  if (buffer_) {
+    int ret = munmap(buffer_, view_size_);
+    DCHECK(0 == ret);
+  }
+}
+
 }  // namespace disk_cache
diff --git a/net/disk_cache/rankings.cc b/net/disk_cache/rankings.cc
index 801d387..b10dac6 100644
--- a/net/disk_cache/rankings.cc
+++ b/net/disk_cache/rankings.cc
@@ -228,58 +228,6 @@
   control_data_ = NULL;
 }
 
-bool Rankings::GetRanking(CacheRankingsBlock* rankings) {
-  if (!rankings->address().is_initialized())
-    return false;
-
-  TimeTicks start = TimeTicks::Now();
-  if (!rankings->Load())
-    return false;
-
-  if (!SanityCheck(rankings, true)) {
-    backend_->CriticalError(ERR_INVALID_LINKS);
-    return false;
-  }
-
-  backend_->OnEvent(Stats::OPEN_RANKINGS);
-
-  // "dummy" is the old "pointer" value, so it has to be 0.
-  if (!rankings->Data()->dirty && !rankings->Data()->dummy)
-    return true;
-
-  EntryImpl* entry = backend_->GetOpenEntry(rankings);
-  if (backend_->GetCurrentEntryId() != rankings->Data()->dirty || !entry) {
-    // We cannot trust this entry, but we cannot initiate a cleanup from this
-    // point (we may be in the middle of a cleanup already). Just get rid of
-    // the invalid pointer and continue; the entry will be deleted when detected
-    // from a regular open/create path.
-    rankings->Data()->dummy = 0;
-    rankings->Data()->dirty = backend_->GetCurrentEntryId() - 1;
-    if (!rankings->Data()->dirty)
-      rankings->Data()->dirty--;
-    return true;
-  }
-
-  // Note that we should not leave this module without deleting rankings first.
-  rankings->SetData(entry->rankings()->Data());
-
-  CACHE_UMA(AGE_MS, "GetRankings", 0, start);
-  return true;
-}
-
-void Rankings::ConvertToLongLived(CacheRankingsBlock* rankings) {
-  if (rankings->own_data())
-    return;
-
-  // We cannot return a shared node because we are not keeping a reference
-  // to the entry that owns the buffer. Make this node a copy of the one that
-  // we have, and let the iterator logic update it when the entry changes.
-  CacheRankingsBlock temp(NULL, Addr(0));
-  *temp.Data() = *rankings->Data();
-  rankings->StopSharingData();
-  *rankings->Data() = *temp.Data();
-}
-
 void Rankings::Insert(CacheRankingsBlock* node, bool modified, List list) {
   Trace("Insert 0x%x l %d", node->address().value(), list);
   DCHECK(node->HasData());
@@ -443,116 +391,6 @@
   CACHE_UMA(AGE_MS, "UpdateRank", 0, start);
 }
 
-void Rankings::CompleteTransaction() {
-  Addr node_addr(static_cast<CacheAddr>(control_data_->transaction));
-  if (!node_addr.is_initialized() || node_addr.is_separate_file()) {
-    NOTREACHED();
-    LOG(ERROR) << "Invalid rankings info.";
-    return;
-  }
-
-  Trace("CompleteTransaction 0x%x", node_addr.value());
-
-  CacheRankingsBlock node(backend_->File(node_addr), node_addr);
-  if (!node.Load())
-    return;
-
-  node.Data()->dummy = 0;
-  node.Store();
-
-  Addr& my_head = heads_[control_data_->operation_list];
-  Addr& my_tail = tails_[control_data_->operation_list];
-
-  // We want to leave the node inside the list. The entry must me marked as
-  // dirty, and will be removed later. Otherwise, we'll get assertions when
-  // attempting to remove the dirty entry.
-  if (INSERT == control_data_->operation) {
-    Trace("FinishInsert h:0x%x t:0x%x", my_head.value(), my_tail.value());
-    FinishInsert(&node);
-  } else if (REMOVE == control_data_->operation) {
-    Trace("RevertRemove h:0x%x t:0x%x", my_head.value(), my_tail.value());
-    RevertRemove(&node);
-  } else {
-    NOTREACHED();
-    LOG(ERROR) << "Invalid operation to recover.";
-  }
-}
-
-void Rankings::FinishInsert(CacheRankingsBlock* node) {
-  control_data_->transaction = 0;
-  control_data_->operation = 0;
-  Addr& my_head = heads_[control_data_->operation_list];
-  Addr& my_tail = tails_[control_data_->operation_list];
-  if (my_head.value() != node->address().value()) {
-    if (my_tail.value() == node->address().value()) {
-      // This part will be skipped by the logic of Insert.
-      node->Data()->next = my_tail.value();
-    }
-
-    Insert(node, true, static_cast<List>(control_data_->operation_list));
-  }
-
-  // Tell the backend about this entry.
-  backend_->RecoveredEntry(node);
-}
-
-void Rankings::RevertRemove(CacheRankingsBlock* node) {
-  Addr next_addr(node->Data()->next);
-  Addr prev_addr(node->Data()->prev);
-  if (!next_addr.is_initialized() || !prev_addr.is_initialized()) {
-    // The operation actually finished. Nothing to do.
-    control_data_->transaction = 0;
-    return;
-  }
-  if (next_addr.is_separate_file() || prev_addr.is_separate_file()) {
-    NOTREACHED();
-    LOG(WARNING) << "Invalid rankings info.";
-    control_data_->transaction = 0;
-    return;
-  }
-
-  CacheRankingsBlock next(backend_->File(next_addr), next_addr);
-  CacheRankingsBlock prev(backend_->File(prev_addr), prev_addr);
-  if (!next.Load() || !prev.Load())
-    return;
-
-  CacheAddr node_value = node->address().value();
-  DCHECK(prev.Data()->next == node_value ||
-         prev.Data()->next == prev_addr.value() ||
-         prev.Data()->next == next.address().value());
-  DCHECK(next.Data()->prev == node_value ||
-         next.Data()->prev == next_addr.value() ||
-         next.Data()->prev == prev.address().value());
-
-  if (node_value != prev_addr.value())
-    prev.Data()->next = node_value;
-  if (node_value != next_addr.value())
-    next.Data()->prev = node_value;
-
-  List my_list = static_cast<List>(control_data_->operation_list);
-  Addr& my_head = heads_[my_list];
-  Addr& my_tail = tails_[my_list];
-  if (!my_head.is_initialized() || !my_tail.is_initialized()) {
-    my_head.set_value(node_value);
-    my_tail.set_value(node_value);
-    WriteHead(my_list);
-    WriteTail(my_list);
-  } else if (my_head.value() == next.address().value()) {
-    my_head.set_value(node_value);
-    prev.Data()->next = next.address().value();
-    WriteHead(my_list);
-  } else if (my_tail.value() == prev.address().value()) {
-    my_tail.set_value(node_value);
-    next.Data()->prev = prev.address().value();
-    WriteTail(my_list);
-  }
-
-  next.Store();
-  prev.Store();
-  control_data_->transaction = 0;
-  control_data_->operation = 0;
-}
-
 CacheRankingsBlock* Rankings::GetNext(CacheRankingsBlock* node, List list) {
   ScopedRankingsBlock next(this);
   if (!node) {
@@ -691,6 +529,168 @@
   control_data_->tails[list] = tails_[list].value();
 }
 
+bool Rankings::GetRanking(CacheRankingsBlock* rankings) {
+  if (!rankings->address().is_initialized())
+    return false;
+
+  TimeTicks start = TimeTicks::Now();
+  if (!rankings->Load())
+    return false;
+
+  if (!SanityCheck(rankings, true)) {
+    backend_->CriticalError(ERR_INVALID_LINKS);
+    return false;
+  }
+
+  backend_->OnEvent(Stats::OPEN_RANKINGS);
+
+  // "dummy" is the old "pointer" value, so it has to be 0.
+  if (!rankings->Data()->dirty && !rankings->Data()->dummy)
+    return true;
+
+  EntryImpl* entry = backend_->GetOpenEntry(rankings);
+  if (backend_->GetCurrentEntryId() != rankings->Data()->dirty || !entry) {
+    // We cannot trust this entry, but we cannot initiate a cleanup from this
+    // point (we may be in the middle of a cleanup already). Just get rid of
+    // the invalid pointer and continue; the entry will be deleted when detected
+    // from a regular open/create path.
+    rankings->Data()->dummy = 0;
+    rankings->Data()->dirty = backend_->GetCurrentEntryId() - 1;
+    if (!rankings->Data()->dirty)
+      rankings->Data()->dirty--;
+    return true;
+  }
+
+  // Note that we should not leave this module without deleting rankings first.
+  rankings->SetData(entry->rankings()->Data());
+
+  CACHE_UMA(AGE_MS, "GetRankings", 0, start);
+  return true;
+}
+
+void Rankings::ConvertToLongLived(CacheRankingsBlock* rankings) {
+  if (rankings->own_data())
+    return;
+
+  // We cannot return a shared node because we are not keeping a reference
+  // to the entry that owns the buffer. Make this node a copy of the one that
+  // we have, and let the iterator logic update it when the entry changes.
+  CacheRankingsBlock temp(NULL, Addr(0));
+  *temp.Data() = *rankings->Data();
+  rankings->StopSharingData();
+  *rankings->Data() = *temp.Data();
+}
+
+void Rankings::CompleteTransaction() {
+  Addr node_addr(static_cast<CacheAddr>(control_data_->transaction));
+  if (!node_addr.is_initialized() || node_addr.is_separate_file()) {
+    NOTREACHED();
+    LOG(ERROR) << "Invalid rankings info.";
+    return;
+  }
+
+  Trace("CompleteTransaction 0x%x", node_addr.value());
+
+  CacheRankingsBlock node(backend_->File(node_addr), node_addr);
+  if (!node.Load())
+    return;
+
+  node.Data()->dummy = 0;
+  node.Store();
+
+  Addr& my_head = heads_[control_data_->operation_list];
+  Addr& my_tail = tails_[control_data_->operation_list];
+
+  // We want to leave the node inside the list. The entry must me marked as
+  // dirty, and will be removed later. Otherwise, we'll get assertions when
+  // attempting to remove the dirty entry.
+  if (INSERT == control_data_->operation) {
+    Trace("FinishInsert h:0x%x t:0x%x", my_head.value(), my_tail.value());
+    FinishInsert(&node);
+  } else if (REMOVE == control_data_->operation) {
+    Trace("RevertRemove h:0x%x t:0x%x", my_head.value(), my_tail.value());
+    RevertRemove(&node);
+  } else {
+    NOTREACHED();
+    LOG(ERROR) << "Invalid operation to recover.";
+  }
+}
+
+void Rankings::FinishInsert(CacheRankingsBlock* node) {
+  control_data_->transaction = 0;
+  control_data_->operation = 0;
+  Addr& my_head = heads_[control_data_->operation_list];
+  Addr& my_tail = tails_[control_data_->operation_list];
+  if (my_head.value() != node->address().value()) {
+    if (my_tail.value() == node->address().value()) {
+      // This part will be skipped by the logic of Insert.
+      node->Data()->next = my_tail.value();
+    }
+
+    Insert(node, true, static_cast<List>(control_data_->operation_list));
+  }
+
+  // Tell the backend about this entry.
+  backend_->RecoveredEntry(node);
+}
+
+void Rankings::RevertRemove(CacheRankingsBlock* node) {
+  Addr next_addr(node->Data()->next);
+  Addr prev_addr(node->Data()->prev);
+  if (!next_addr.is_initialized() || !prev_addr.is_initialized()) {
+    // The operation actually finished. Nothing to do.
+    control_data_->transaction = 0;
+    return;
+  }
+  if (next_addr.is_separate_file() || prev_addr.is_separate_file()) {
+    NOTREACHED();
+    LOG(WARNING) << "Invalid rankings info.";
+    control_data_->transaction = 0;
+    return;
+  }
+
+  CacheRankingsBlock next(backend_->File(next_addr), next_addr);
+  CacheRankingsBlock prev(backend_->File(prev_addr), prev_addr);
+  if (!next.Load() || !prev.Load())
+    return;
+
+  CacheAddr node_value = node->address().value();
+  DCHECK(prev.Data()->next == node_value ||
+         prev.Data()->next == prev_addr.value() ||
+         prev.Data()->next == next.address().value());
+  DCHECK(next.Data()->prev == node_value ||
+         next.Data()->prev == next_addr.value() ||
+         next.Data()->prev == prev.address().value());
+
+  if (node_value != prev_addr.value())
+    prev.Data()->next = node_value;
+  if (node_value != next_addr.value())
+    next.Data()->prev = node_value;
+
+  List my_list = static_cast<List>(control_data_->operation_list);
+  Addr& my_head = heads_[my_list];
+  Addr& my_tail = tails_[my_list];
+  if (!my_head.is_initialized() || !my_tail.is_initialized()) {
+    my_head.set_value(node_value);
+    my_tail.set_value(node_value);
+    WriteHead(my_list);
+    WriteTail(my_list);
+  } else if (my_head.value() == next.address().value()) {
+    my_head.set_value(node_value);
+    prev.Data()->next = next.address().value();
+    WriteHead(my_list);
+  } else if (my_tail.value() == prev.address().value()) {
+    my_tail.set_value(node_value);
+    next.Data()->prev = prev.address().value();
+    WriteTail(my_list);
+  }
+
+  next.Store();
+  prev.Store();
+  control_data_->transaction = 0;
+  control_data_->operation = 0;
+}
+
 bool Rankings::CheckEntry(CacheRankingsBlock* rankings) {
   if (!rankings->Data()->dummy)
     return true;
diff --git a/net/disk_cache/stats.cc b/net/disk_cache/stats.cc
index 5222112..d9a9d12 100644
--- a/net/disk_cache/stats.cc
+++ b/net/disk_cache/stats.cc
@@ -116,6 +116,12 @@
   return StoreStats(backend, *address, stats);
 }
 
+Stats::Stats() : backend_(NULL) {
+}
+
+Stats::~Stats() {
+}
+
 bool Stats::Init(BackendImpl* backend, uint32* storage_addr) {
   OnDiskStats stats;
   Addr address(*storage_addr);
@@ -153,86 +159,6 @@
   return true;
 }
 
-Stats::Stats() : backend_(NULL) {
-}
-
-Stats::~Stats() {
-}
-
-// The array will be filled this way:
-//  index      size
-//    0       [0, 1024)
-//    1    [1024, 2048)
-//    2    [2048, 4096)
-//    3      [4K, 6K)
-//      ...
-//   10     [18K, 20K)
-//   11     [20K, 24K)
-//   12     [24k, 28K)
-//      ...
-//   15     [36k, 40K)
-//   16     [40k, 64K)
-//   17     [64K, 128K)
-//   18    [128K, 256K)
-//      ...
-//   23      [4M, 8M)
-//   24      [8M, 16M)
-//   25     [16M, 32M)
-//   26     [32M, 64M)
-//   27     [64M, ...)
-int Stats::GetStatsBucket(int32 size) {
-  if (size < 1024)
-    return 0;
-
-  // 10 slots more, until 20K.
-  if (size < 20 * 1024)
-    return size / 2048 + 1;
-
-  // 5 slots more, from 20K to 40K.
-  if (size < 40 * 1024)
-    return (size - 20 * 1024) / 4096 + 11;
-
-  // From this point on, use a logarithmic scale.
-  int result =  LogBase2(size) + 1;
-
-  COMPILE_ASSERT(kDataSizesLength > 16, update_the_scale);
-  if (result >= kDataSizesLength)
-    result = kDataSizesLength - 1;
-
-  return result;
-}
-
-int Stats::GetBucketRange(size_t i) const {
-  if (i < 2)
-    return static_cast<int>(1024 * i);
-
-  if (i < 12)
-    return static_cast<int>(2048 * (i - 1));
-
-  if (i < 17)
-    return static_cast<int>(4096 * (i - 11)) + 20 * 1024;
-
-  int n = 64 * 1024;
-  if (i > static_cast<size_t>(kDataSizesLength)) {
-    NOTREACHED();
-    i = kDataSizesLength;
-  }
-
-  i -= 17;
-  n <<= i;
-  return n;
-}
-
-void Stats::Snapshot(StatsHistogram::StatsSamples* samples) const {
-  samples->GetCounts()->resize(kDataSizesLength);
-  for (int i = 0; i < kDataSizesLength; i++) {
-    int count = data_sizes_[i];
-    if (count < 0)
-      count = 0;
-    samples->GetCounts()->at(i) = count;
-  }
-}
-
 void Stats::ModifyStorageStats(int32 old_size, int32 new_size) {
   // We keep a counter of the data block size on an array where each entry is
   // the adjusted log base 2 of the size. The first entry counts blocks of 256
@@ -286,15 +212,6 @@
   return GetRatio(RESURRECT_HIT, CREATE_HIT);
 }
 
-int Stats::GetRatio(Counters hit, Counters miss) const {
-  int64 ratio = GetCounter(hit) * 100;
-  if (!ratio)
-    return 0;
-
-  ratio /= (GetCounter(hit) + GetCounter(miss));
-  return static_cast<int>(ratio);
-}
-
 void Stats::ResetRatios() {
   SetCounter(OPEN_HIT, 0);
   SetCounter(OPEN_MISS, 0);
@@ -326,4 +243,87 @@
   StoreStats(backend_, address, &stats);
 }
 
+int Stats::GetBucketRange(size_t i) const {
+  if (i < 2)
+    return static_cast<int>(1024 * i);
+
+  if (i < 12)
+    return static_cast<int>(2048 * (i - 1));
+
+  if (i < 17)
+    return static_cast<int>(4096 * (i - 11)) + 20 * 1024;
+
+  int n = 64 * 1024;
+  if (i > static_cast<size_t>(kDataSizesLength)) {
+    NOTREACHED();
+    i = kDataSizesLength;
+  }
+
+  i -= 17;
+  n <<= i;
+  return n;
+}
+
+void Stats::Snapshot(StatsHistogram::StatsSamples* samples) const {
+  samples->GetCounts()->resize(kDataSizesLength);
+  for (int i = 0; i < kDataSizesLength; i++) {
+    int count = data_sizes_[i];
+    if (count < 0)
+      count = 0;
+    samples->GetCounts()->at(i) = count;
+  }
+}
+
+// The array will be filled this way:
+//  index      size
+//    0       [0, 1024)
+//    1    [1024, 2048)
+//    2    [2048, 4096)
+//    3      [4K, 6K)
+//      ...
+//   10     [18K, 20K)
+//   11     [20K, 24K)
+//   12     [24k, 28K)
+//      ...
+//   15     [36k, 40K)
+//   16     [40k, 64K)
+//   17     [64K, 128K)
+//   18    [128K, 256K)
+//      ...
+//   23      [4M, 8M)
+//   24      [8M, 16M)
+//   25     [16M, 32M)
+//   26     [32M, 64M)
+//   27     [64M, ...)
+int Stats::GetStatsBucket(int32 size) {
+  if (size < 1024)
+    return 0;
+
+  // 10 slots more, until 20K.
+  if (size < 20 * 1024)
+    return size / 2048 + 1;
+
+  // 5 slots more, from 20K to 40K.
+  if (size < 40 * 1024)
+    return (size - 20 * 1024) / 4096 + 11;
+
+  // From this point on, use a logarithmic scale.
+  int result =  LogBase2(size) + 1;
+
+  COMPILE_ASSERT(kDataSizesLength > 16, update_the_scale);
+  if (result >= kDataSizesLength)
+    result = kDataSizesLength - 1;
+
+  return result;
+}
+
+int Stats::GetRatio(Counters hit, Counters miss) const {
+  int64 ratio = GetCounter(hit) * 100;
+  if (!ratio)
+    return 0;
+
+  ratio /= (GetCounter(hit) + GetCounter(miss));
+  return static_cast<int>(ratio);
+}
+
 }  // namespace disk_cache
diff --git a/net/ftp/ftp_directory_listing_parser_vms.h b/net/ftp/ftp_directory_listing_parser_vms.h
index 118365d..6f7fb73 100644
--- a/net/ftp/ftp_directory_listing_parser_vms.h
+++ b/net/ftp/ftp_directory_listing_parser_vms.h
@@ -26,10 +26,6 @@
   virtual FtpDirectoryListingEntry PopEntry();
 
  private:
-  // Consumes listing line which is expected to be a directory listing entry
-  // (and not a comment etc). Returns true on success.
-  bool ConsumeEntryLine(const string16& line);
-
   enum State {
     STATE_INITIAL,
 
@@ -46,7 +42,13 @@
 
     // Indicates that we have successfully received all parts of the listing.
     STATE_END,
-  } state_;
+  };
+
+  // Consumes listing line which is expected to be a directory listing entry
+  // (and not a comment etc). Returns true on success.
+  bool ConsumeEntryLine(const string16& line);
+
+  State state_;
 
   // VMS can use two physical lines if the filename is long. The first line will
   // contain the filename, and the second line everything else. Store the
diff --git a/net/ftp/ftp_network_transaction.cc b/net/ftp/ftp_network_transaction.cc
index 0285e08a..d012818 100644
--- a/net/ftp/ftp_network_transaction.cc
+++ b/net/ftp/ftp_network_transaction.cc
@@ -204,6 +204,20 @@
 FtpNetworkTransaction::~FtpNetworkTransaction() {
 }
 
+int FtpNetworkTransaction::Stop(int error) {
+  if (command_sent_ == COMMAND_QUIT)
+    return error;
+
+  next_state_ = STATE_CTRL_WRITE_QUIT;
+  last_error_ = error;
+  return OK;
+}
+
+int FtpNetworkTransaction::RestartIgnoringLastError(
+    CompletionCallback* callback) {
+  return ERR_NOT_IMPLEMENTED;
+}
+
 int FtpNetworkTransaction::Start(const FtpRequestInfo* request_info,
                                  CompletionCallback* callback,
                                  const BoundNetLog& net_log) {
@@ -226,15 +240,6 @@
   return rv;
 }
 
-int FtpNetworkTransaction::Stop(int error) {
-  if (command_sent_ == COMMAND_QUIT)
-    return error;
-
-  next_state_ = STATE_CTRL_WRITE_QUIT;
-  last_error_ = error;
-  return OK;
-}
-
 int FtpNetworkTransaction::RestartWithAuth(const string16& username,
                                            const string16& password,
                                            CompletionCallback* callback) {
@@ -250,11 +255,6 @@
   return rv;
 }
 
-int FtpNetworkTransaction::RestartIgnoringLastError(
-    CompletionCallback* callback) {
-  return ERR_NOT_IMPLEMENTED;
-}
-
 int FtpNetworkTransaction::Read(IOBuffer* buf,
                                 int buf_len,
                                 CompletionCallback* callback) {
@@ -302,34 +302,37 @@
   return 0;
 }
 
-// Used to prepare and send FTP command.
-int FtpNetworkTransaction::SendFtpCommand(const std::string& command,
-                                          Command cmd) {
-  // If we send a new command when we still have unprocessed responses
-  // for previous commands, the response receiving code will have no way to know
-  // which responses are for which command.
-  DCHECK(!ctrl_response_buffer_->ResponseAvailable());
+void FtpNetworkTransaction::ResetStateForRestart() {
+  command_sent_ = COMMAND_NONE;
+  user_callback_ = NULL;
+  response_ = FtpResponseInfo();
+  read_ctrl_buf_ = new IOBuffer(kCtrlBufLen);
+  ctrl_response_buffer_.reset(new FtpCtrlResponseBuffer());
+  read_data_buf_ = NULL;
+  read_data_buf_len_ = 0;
+  if (write_buf_)
+    write_buf_->SetOffset(0);
+  last_error_ = OK;
+  data_connection_port_ = 0;
+  ctrl_socket_.reset();
+  data_socket_.reset();
+  next_state_ = STATE_NONE;
+}
 
-  DCHECK(!write_command_buf_);
-  DCHECK(!write_buf_);
+void FtpNetworkTransaction::DoCallback(int rv) {
+  DCHECK(rv != ERR_IO_PENDING);
+  DCHECK(user_callback_);
 
-  if (!IsValidFTPCommandString(command)) {
-    // Callers should validate the command themselves and return a more specific
-    // error code.
-    NOTREACHED();
-    return Stop(ERR_UNEXPECTED);
-  }
+  // Since Run may result in Read being called, clear callback_ up front.
+  CompletionCallback* c = user_callback_;
+  user_callback_ = NULL;
+  c->Run(rv);
+}
 
-  command_sent_ = cmd;
-
-  write_command_buf_ = new IOBufferWithSize(command.length() + 2);
-  write_buf_ = new DrainableIOBuffer(write_command_buf_,
-                                     write_command_buf_->size());
-  memcpy(write_command_buf_->data(), command.data(), command.length());
-  memcpy(write_command_buf_->data() + command.length(), kCRLF, 2);
-
-  next_state_ = STATE_CTRL_WRITE;
-  return OK;
+void FtpNetworkTransaction::OnIOComplete(int result) {
+  int rv = DoLoop(result);
+  if (rv != ERR_IO_PENDING)
+    DoCallback(rv);
 }
 
 int FtpNetworkTransaction::ProcessCtrlResponse() {
@@ -403,37 +406,34 @@
   return rv;
 }
 
-void FtpNetworkTransaction::ResetStateForRestart() {
-  command_sent_ = COMMAND_NONE;
-  user_callback_ = NULL;
-  response_ = FtpResponseInfo();
-  read_ctrl_buf_ = new IOBuffer(kCtrlBufLen);
-  ctrl_response_buffer_.reset(new FtpCtrlResponseBuffer());
-  read_data_buf_ = NULL;
-  read_data_buf_len_ = 0;
-  if (write_buf_)
-    write_buf_->SetOffset(0);
-  last_error_ = OK;
-  data_connection_port_ = 0;
-  ctrl_socket_.reset();
-  data_socket_.reset();
-  next_state_ = STATE_NONE;
-}
+// Used to prepare and send FTP command.
+int FtpNetworkTransaction::SendFtpCommand(const std::string& command,
+                                          Command cmd) {
+  // If we send a new command when we still have unprocessed responses
+  // for previous commands, the response receiving code will have no way to know
+  // which responses are for which command.
+  DCHECK(!ctrl_response_buffer_->ResponseAvailable());
 
-void FtpNetworkTransaction::DoCallback(int rv) {
-  DCHECK(rv != ERR_IO_PENDING);
-  DCHECK(user_callback_);
+  DCHECK(!write_command_buf_);
+  DCHECK(!write_buf_);
 
-  // Since Run may result in Read being called, clear callback_ up front.
-  CompletionCallback* c = user_callback_;
-  user_callback_ = NULL;
-  c->Run(rv);
-}
+  if (!IsValidFTPCommandString(command)) {
+    // Callers should validate the command themselves and return a more specific
+    // error code.
+    NOTREACHED();
+    return Stop(ERR_UNEXPECTED);
+  }
 
-void FtpNetworkTransaction::OnIOComplete(int result) {
-  int rv = DoLoop(result);
-  if (rv != ERR_IO_PENDING)
-    DoCallback(rv);
+  command_sent_ = cmd;
+
+  write_command_buf_ = new IOBufferWithSize(command.length() + 2);
+  write_buf_ = new DrainableIOBuffer(write_command_buf_,
+                                     write_command_buf_->size());
+  memcpy(write_command_buf_->data(), command.data(), command.length());
+  memcpy(write_command_buf_->data() + command.length(), kCRLF, 2);
+
+  next_state_ = STATE_CTRL_WRITE;
+  return OK;
 }
 
 std::string FtpNetworkTransaction::GetRequestPathForFtpCommand(
@@ -947,56 +947,6 @@
   return OK;
 }
 
-// SIZE command
-int FtpNetworkTransaction::DoCtrlWriteSIZE() {
-  std::string command = "SIZE " + GetRequestPathForFtpCommand(false);
-  next_state_ = STATE_CTRL_READ;
-  return SendFtpCommand(command, COMMAND_SIZE);
-}
-
-int FtpNetworkTransaction::ProcessResponseSIZE(
-    const FtpCtrlResponse& response) {
-  switch (GetErrorClass(response.status_code)) {
-    case ERROR_CLASS_INITIATED:
-      break;
-    case ERROR_CLASS_OK:
-      if (response.lines.size() != 1)
-        return Stop(ERR_INVALID_RESPONSE);
-      int64 size;
-      if (!base::StringToInt64(response.lines[0], &size))
-        return Stop(ERR_INVALID_RESPONSE);
-      if (size < 0)
-        return Stop(ERR_INVALID_RESPONSE);
-
-      // A successful response to SIZE does not mean the resource is a file.
-      // Some FTP servers (for example, the qnx one) send a SIZE even for
-      // directories.
-      response_.expected_content_size = size;
-      break;
-    case ERROR_CLASS_INFO_NEEDED:
-      break;
-    case ERROR_CLASS_TRANSIENT_ERROR:
-      break;
-    case ERROR_CLASS_PERMANENT_ERROR:
-      // It's possible that SIZE failed because the path is a directory.
-      if (resource_type_ == RESOURCE_TYPE_UNKNOWN &&
-          response.status_code != 550) {
-        return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
-      }
-      break;
-    default:
-      NOTREACHED();
-      return Stop(ERR_UNEXPECTED);
-  }
-
-  if (resource_type_ == RESOURCE_TYPE_FILE)
-    next_state_ = STATE_CTRL_WRITE_RETR;
-  else
-    next_state_ = STATE_CTRL_WRITE_CWD;
-
-  return OK;
-}
-
 // RETR command
 int FtpNetworkTransaction::DoCtrlWriteRETR() {
   std::string command = "RETR " + GetRequestPathForFtpCommand(false);
@@ -1048,6 +998,56 @@
   return OK;
 }
 
+// SIZE command
+int FtpNetworkTransaction::DoCtrlWriteSIZE() {
+  std::string command = "SIZE " + GetRequestPathForFtpCommand(false);
+  next_state_ = STATE_CTRL_READ;
+  return SendFtpCommand(command, COMMAND_SIZE);
+}
+
+int FtpNetworkTransaction::ProcessResponseSIZE(
+    const FtpCtrlResponse& response) {
+  switch (GetErrorClass(response.status_code)) {
+    case ERROR_CLASS_INITIATED:
+      break;
+    case ERROR_CLASS_OK:
+      if (response.lines.size() != 1)
+        return Stop(ERR_INVALID_RESPONSE);
+      int64 size;
+      if (!base::StringToInt64(response.lines[0], &size))
+        return Stop(ERR_INVALID_RESPONSE);
+      if (size < 0)
+        return Stop(ERR_INVALID_RESPONSE);
+
+      // A successful response to SIZE does not mean the resource is a file.
+      // Some FTP servers (for example, the qnx one) send a SIZE even for
+      // directories.
+      response_.expected_content_size = size;
+      break;
+    case ERROR_CLASS_INFO_NEEDED:
+      break;
+    case ERROR_CLASS_TRANSIENT_ERROR:
+      break;
+    case ERROR_CLASS_PERMANENT_ERROR:
+      // It's possible that SIZE failed because the path is a directory.
+      if (resource_type_ == RESOURCE_TYPE_UNKNOWN &&
+          response.status_code != 550) {
+        return Stop(GetNetErrorCodeForFtpResponseCode(response.status_code));
+      }
+      break;
+    default:
+      NOTREACHED();
+      return Stop(ERR_UNEXPECTED);
+  }
+
+  if (resource_type_ == RESOURCE_TYPE_FILE)
+    next_state_ = STATE_CTRL_WRITE_RETR;
+  else
+    next_state_ = STATE_CTRL_WRITE_CWD;
+
+  return OK;
+}
+
 // CWD command
 int FtpNetworkTransaction::DoCtrlWriteCWD() {
   std::string command = "CWD " + GetRequestPathForFtpCommand(true);
diff --git a/net/ftp/ftp_network_transaction.h b/net/ftp/ftp_network_transaction.h
index 678308a..c4516a45 100644
--- a/net/ftp/ftp_network_transaction.h
+++ b/net/ftp/ftp_network_transaction.h
@@ -31,15 +31,16 @@
                         ClientSocketFactory* socket_factory);
   virtual ~FtpNetworkTransaction();
 
+  virtual int Stop(int error);
+  virtual int RestartIgnoringLastError(CompletionCallback* callback);
+
   // FtpTransaction methods:
   virtual int Start(const FtpRequestInfo* request_info,
                     CompletionCallback* callback,
                     const BoundNetLog& net_log);
-  virtual int Stop(int error);
   virtual int RestartWithAuth(const string16& username,
                               const string16& password,
                               CompletionCallback* callback);
-  virtual int RestartIgnoringLastError(CompletionCallback* callback);
   virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
   virtual const FtpResponseInfo* GetResponseInfo() const;
   virtual LoadState GetLoadState() const;
@@ -87,6 +88,36 @@
     RESOURCE_TYPE_DIRECTORY,
   };
 
+  enum State {
+    // Control connection states:
+    STATE_CTRL_RESOLVE_HOST,
+    STATE_CTRL_RESOLVE_HOST_COMPLETE,
+    STATE_CTRL_CONNECT,
+    STATE_CTRL_CONNECT_COMPLETE,
+    STATE_CTRL_READ,
+    STATE_CTRL_READ_COMPLETE,
+    STATE_CTRL_WRITE,
+    STATE_CTRL_WRITE_COMPLETE,
+    STATE_CTRL_WRITE_USER,
+    STATE_CTRL_WRITE_PASS,
+    STATE_CTRL_WRITE_SYST,
+    STATE_CTRL_WRITE_TYPE,
+    STATE_CTRL_WRITE_EPSV,
+    STATE_CTRL_WRITE_PASV,
+    STATE_CTRL_WRITE_PWD,
+    STATE_CTRL_WRITE_RETR,
+    STATE_CTRL_WRITE_SIZE,
+    STATE_CTRL_WRITE_CWD,
+    STATE_CTRL_WRITE_LIST,
+    STATE_CTRL_WRITE_QUIT,
+    // Data connection states:
+    STATE_DATA_CONNECT,
+    STATE_DATA_CONNECT_COMPLETE,
+    STATE_DATA_READ,
+    STATE_DATA_READ_COMPLETE,
+    STATE_NONE
+  };
+
   // Resets the members of the transaction so it can be restarted.
   void ResetStateForRestart();
 
@@ -211,35 +242,6 @@
   scoped_ptr<ClientSocket> ctrl_socket_;
   scoped_ptr<ClientSocket> data_socket_;
 
-  enum State {
-    // Control connection states:
-    STATE_CTRL_RESOLVE_HOST,
-    STATE_CTRL_RESOLVE_HOST_COMPLETE,
-    STATE_CTRL_CONNECT,
-    STATE_CTRL_CONNECT_COMPLETE,
-    STATE_CTRL_READ,
-    STATE_CTRL_READ_COMPLETE,
-    STATE_CTRL_WRITE,
-    STATE_CTRL_WRITE_COMPLETE,
-    STATE_CTRL_WRITE_USER,
-    STATE_CTRL_WRITE_PASS,
-    STATE_CTRL_WRITE_SYST,
-    STATE_CTRL_WRITE_TYPE,
-    STATE_CTRL_WRITE_EPSV,
-    STATE_CTRL_WRITE_PASV,
-    STATE_CTRL_WRITE_PWD,
-    STATE_CTRL_WRITE_RETR,
-    STATE_CTRL_WRITE_SIZE,
-    STATE_CTRL_WRITE_CWD,
-    STATE_CTRL_WRITE_LIST,
-    STATE_CTRL_WRITE_QUIT,
-    // Data connection states:
-    STATE_DATA_CONNECT,
-    STATE_DATA_CONNECT_COMPLETE,
-    STATE_DATA_READ,
-    STATE_DATA_READ_COMPLETE,
-    STATE_NONE
-  };
   State next_state_;
 };
 
diff --git a/net/http/disk_cache_based_ssl_host_info.cc b/net/http/disk_cache_based_ssl_host_info.cc
index 1b1dfaf..1a875cba 100644
--- a/net/http/disk_cache_based_ssl_host_info.cc
+++ b/net/http/disk_cache_based_ssl_host_info.cc
@@ -13,6 +13,24 @@
 
 namespace net {
 
+DiskCacheBasedSSLHostInfo::CallbackImpl::CallbackImpl(
+    const base::WeakPtr<DiskCacheBasedSSLHostInfo>& obj,
+    void (DiskCacheBasedSSLHostInfo::*meth) (int))
+    : obj_(obj),
+      meth_(meth) {
+}
+
+DiskCacheBasedSSLHostInfo::CallbackImpl::~CallbackImpl() {}
+
+void DiskCacheBasedSSLHostInfo::CallbackImpl::RunWithParams(
+    const Tuple1<int>& params) {
+  if (!obj_) {
+    delete this;
+  } else {
+    DispatchToMethod(obj_.get(), meth_, params);
+  }
+}
+
 DiskCacheBasedSSLHostInfo::DiskCacheBasedSSLHostInfo(
     const std::string& hostname,
     const SSLConfig& ssl_config,
@@ -37,6 +55,35 @@
   DoLoop(OK);
 }
 
+int DiskCacheBasedSSLHostInfo::WaitForDataReady(CompletionCallback* callback) {
+  DCHECK(CalledOnValidThread());
+  DCHECK(state_ != GET_BACKEND);
+
+  if (ready_)
+    return OK;
+  if (callback) {
+    DCHECK(!user_callback_);
+    user_callback_ = callback;
+  }
+  return ERR_IO_PENDING;
+}
+
+void DiskCacheBasedSSLHostInfo::Persist() {
+  DCHECK(CalledOnValidThread());
+  DCHECK(state_ != GET_BACKEND);
+
+  DCHECK(new_data_.empty());
+  CHECK(ready_);
+  DCHECK(user_callback_ == NULL);
+  new_data_ = Serialize();
+
+  if (!backend_)
+    return;
+
+  state_ = CREATE;
+  DoLoop(OK);
+}
+
 DiskCacheBasedSSLHostInfo::~DiskCacheBasedSSLHostInfo() {
   DCHECK(!user_callback_);
   if (entry_)
@@ -95,24 +142,6 @@
   } while (rv != ERR_IO_PENDING && state_ != NONE);
 }
 
-bool DiskCacheBasedSSLHostInfo::IsCallbackPending() const {
-  switch (state_) {
-    case GET_BACKEND_COMPLETE:
-    case OPEN_COMPLETE:
-    case READ_COMPLETE:
-    case CREATE_COMPLETE:
-    case WRITE_COMPLETE:
-      return true;
-    default:
-      return false;
-  }
-}
-
-int DiskCacheBasedSSLHostInfo::DoGetBackend() {
-  state_ = GET_BACKEND_COMPLETE;
-  return http_cache_->GetBackend(callback_->backend_pointer(), callback_);
-}
-
 int DiskCacheBasedSSLHostInfo::DoGetBackendComplete(int rv) {
   if (rv == OK) {
     backend_ = callback_->backend();
@@ -123,11 +152,6 @@
   return OK;
 }
 
-int DiskCacheBasedSSLHostInfo::DoOpen() {
-  state_ = OPEN_COMPLETE;
-  return backend_->OpenEntry(key(), callback_->entry_pointer(), callback_);
-}
-
 int DiskCacheBasedSSLHostInfo::DoOpenComplete(int rv) {
   if (rv == OK) {
     entry_ = callback_->entry();
@@ -139,6 +163,39 @@
   return OK;
 }
 
+int DiskCacheBasedSSLHostInfo::DoReadComplete(int rv) {
+  if (rv > 0)
+    data_ = std::string(read_buffer_->data(), rv);
+
+  state_ = WAIT_FOR_DATA_READY_DONE;
+  return OK;
+}
+
+int DiskCacheBasedSSLHostInfo::DoWriteComplete(int rv) {
+  state_ = SET_DONE;
+  return OK;
+}
+
+int DiskCacheBasedSSLHostInfo::DoCreateComplete(int rv) {
+  if (rv != OK) {
+    state_ = SET_DONE;
+  } else {
+    entry_ = callback_->entry();
+    state_ = WRITE;
+  }
+  return OK;
+}
+
+int DiskCacheBasedSSLHostInfo::DoGetBackend() {
+  state_ = GET_BACKEND_COMPLETE;
+  return http_cache_->GetBackend(callback_->backend_pointer(), callback_);
+}
+
+int DiskCacheBasedSSLHostInfo::DoOpen() {
+  state_ = OPEN_COMPLETE;
+  return backend_->OpenEntry(key(), callback_->entry_pointer(), callback_);
+}
+
 int DiskCacheBasedSSLHostInfo::DoRead() {
   const int32 size = entry_->GetDataSize(0 /* index */);
   if (!size) {
@@ -152,12 +209,19 @@
                           size, callback_);
 }
 
-int DiskCacheBasedSSLHostInfo::DoReadComplete(int rv) {
-  if (rv > 0)
-    data_ = std::string(read_buffer_->data(), rv);
+int DiskCacheBasedSSLHostInfo::DoWrite() {
+  write_buffer_ = new IOBuffer(new_data_.size());
+  memcpy(write_buffer_->data(), new_data_.data(), new_data_.size());
+  state_ = WRITE_COMPLETE;
 
-  state_ = WAIT_FOR_DATA_READY_DONE;
-  return OK;
+  return entry_->WriteData(0 /* index */, 0 /* offset */, write_buffer_,
+                           new_data_.size(), callback_, true /* truncate */);
+}
+
+int DiskCacheBasedSSLHostInfo::DoCreate() {
+  DCHECK(entry_ == NULL);
+  state_ = CREATE_COMPLETE;
+  return backend_->CreateEntry(key(), callback_->entry_pointer(), callback_);
 }
 
 int DiskCacheBasedSSLHostInfo::WaitForDataReadyDone() {
@@ -181,65 +245,6 @@
   return OK;
 }
 
-int DiskCacheBasedSSLHostInfo::WaitForDataReady(CompletionCallback* callback) {
-  DCHECK(CalledOnValidThread());
-  DCHECK(state_ != GET_BACKEND);
-
-  if (ready_)
-    return OK;
-  if (callback) {
-    DCHECK(!user_callback_);
-    user_callback_ = callback;
-  }
-  return ERR_IO_PENDING;
-}
-
-void DiskCacheBasedSSLHostInfo::Persist() {
-  DCHECK(CalledOnValidThread());
-  DCHECK(state_ != GET_BACKEND);
-
-  DCHECK(new_data_.empty());
-  CHECK(ready_);
-  DCHECK(user_callback_ == NULL);
-  new_data_ = Serialize();
-
-  if (!backend_)
-    return;
-
-  state_ = CREATE;
-  DoLoop(OK);
-}
-
-int DiskCacheBasedSSLHostInfo::DoCreate() {
-  DCHECK(entry_ == NULL);
-  state_ = CREATE_COMPLETE;
-  return backend_->CreateEntry(key(), callback_->entry_pointer(), callback_);
-}
-
-int DiskCacheBasedSSLHostInfo::DoCreateComplete(int rv) {
-  if (rv != OK) {
-    state_ = SET_DONE;
-  } else {
-    entry_ = callback_->entry();
-    state_ = WRITE;
-  }
-  return OK;
-}
-
-int DiskCacheBasedSSLHostInfo::DoWrite() {
-  write_buffer_ = new IOBuffer(new_data_.size());
-  memcpy(write_buffer_->data(), new_data_.data(), new_data_.size());
-  state_ = WRITE_COMPLETE;
-
-  return entry_->WriteData(0 /* index */, 0 /* offset */, write_buffer_,
-                           new_data_.size(), callback_, true /* truncate */);
-}
-
-int DiskCacheBasedSSLHostInfo::DoWriteComplete(int rv) {
-  state_ = SET_DONE;
-  return OK;
-}
-
 int DiskCacheBasedSSLHostInfo::SetDone() {
   if (entry_)
     entry_->Close();
@@ -248,4 +253,17 @@
   return OK;
 }
 
+bool DiskCacheBasedSSLHostInfo::IsCallbackPending() const {
+  switch (state_) {
+    case GET_BACKEND_COMPLETE:
+    case OPEN_COMPLETE:
+    case READ_COMPLETE:
+    case CREATE_COMPLETE:
+    case WRITE_COMPLETE:
+      return true;
+    default:
+      return false;
+  }
+}
+
 } // namespace net
diff --git a/net/http/disk_cache_based_ssl_host_info.h b/net/http/disk_cache_based_ssl_host_info.h
index 2beb7e4..9d04ba0 100644
--- a/net/http/disk_cache_based_ssl_host_info.h
+++ b/net/http/disk_cache_based_ssl_host_info.h
@@ -52,29 +52,20 @@
     NONE,
   };
 
-  ~DiskCacheBasedSSLHostInfo();
-
   class CallbackImpl : public CallbackRunner<Tuple1<int> > {
    public:
     CallbackImpl(const base::WeakPtr<DiskCacheBasedSSLHostInfo>& obj,
-                 void (DiskCacheBasedSSLHostInfo::*meth) (int))
-        : obj_(obj),
-          meth_(meth) {
-    }
-
-    virtual void RunWithParams(const Tuple1<int>& params) {
-      if (!obj_) {
-        delete this;
-      } else {
-        DispatchToMethod(obj_.get(), meth_, params);
-      }
-    }
+                 void (DiskCacheBasedSSLHostInfo::*meth) (int));
+    virtual ~CallbackImpl();
 
     disk_cache::Backend** backend_pointer() { return &backend_; }
     disk_cache::Entry** entry_pointer() { return &entry_; }
     disk_cache::Backend* backend() const { return backend_; }
     disk_cache::Entry* entry() const { return entry_; }
 
+    // CallbackRunner<Tuple1<int> >:
+    virtual void RunWithParams(const Tuple1<int>& params);
+
    private:
     base::WeakPtr<DiskCacheBasedSSLHostInfo> obj_;
     void (DiskCacheBasedSSLHostInfo::*meth_) (int);
@@ -83,6 +74,8 @@
     disk_cache::Entry* entry_;
   };
 
+  virtual ~DiskCacheBasedSSLHostInfo();
+
   std::string key() const;
 
   void DoLoop(int rv);
@@ -96,11 +89,12 @@
   int DoGetBackend();
   int DoOpen();
   int DoRead();
-  int DoCreate();
   int DoWrite();
+  int DoCreate();
 
   // WaitForDataReadyDone is the terminal state of the read operation.
   int WaitForDataReadyDone();
+
   // SetDone is the terminal state of the write operation.
   int SetDone();
 
diff --git a/net/http/http_auth_filter.cc b/net/http/http_auth_filter.cc
index a61e7f7..2109e4d 100644
--- a/net/http/http_auth_filter.cc
+++ b/net/http/http_auth_filter.cc
@@ -24,21 +24,6 @@
 HttpAuthFilterWhitelist::~HttpAuthFilterWhitelist() {
 }
 
-void HttpAuthFilterWhitelist::SetWhitelist(
-    const std::string& server_whitelist) {
-  rules_.ParseFromString(server_whitelist);
-}
-
-bool HttpAuthFilterWhitelist::IsValid(const GURL& url,
-                                      HttpAuth::Target target) const {
-  if ((target != HttpAuth::AUTH_SERVER) && (target != HttpAuth::AUTH_PROXY))
-    return false;
-  // All proxies pass
-  if (target == HttpAuth::AUTH_PROXY)
-    return true;
-  return rules_.Matches(url);
-}
-
 // Add a new domain |filter| to the whitelist, if it's not already there
 bool HttpAuthFilterWhitelist::AddFilter(const std::string& filter,
                                         HttpAuth::Target target) {
@@ -55,4 +40,19 @@
   rules_.AddRuleToBypassLocal();
 }
 
+bool HttpAuthFilterWhitelist::IsValid(const GURL& url,
+                                      HttpAuth::Target target) const {
+  if ((target != HttpAuth::AUTH_SERVER) && (target != HttpAuth::AUTH_PROXY))
+    return false;
+  // All proxies pass
+  if (target == HttpAuth::AUTH_PROXY)
+    return true;
+  return rules_.Matches(url);
+}
+
+void HttpAuthFilterWhitelist::SetWhitelist(
+    const std::string& server_whitelist) {
+  rules_.ParseFromString(server_whitelist);
+}
+
 }  // namespace net
diff --git a/net/http/http_auth_filter.h b/net/http/http_auth_filter.h
index 334bc91..81d414c2e 100644
--- a/net/http/http_auth_filter.h
+++ b/net/http/http_auth_filter.h
@@ -37,9 +37,6 @@
   explicit HttpAuthFilterWhitelist(const std::string& server_whitelist);
   virtual ~HttpAuthFilterWhitelist();
 
-  // HttpAuthFilter methods:
-  virtual bool IsValid(const GURL& url, HttpAuth::Target target) const;
-
   // Adds an individual URL |filter| to the list, of the specified |target|.
   bool AddFilter(const std::string& filter, HttpAuth::Target target);
 
@@ -48,6 +45,9 @@
 
   const ProxyBypassRules& rules() const { return rules_; }
 
+  // HttpAuthFilter methods:
+  virtual bool IsValid(const GURL& url, HttpAuth::Target target) const;
+
  private:
   // Installs the whitelist.
   // |server_whitelist| is parsed by ProxyBypassRules.
diff --git a/net/http/http_auth_handler_digest.cc b/net/http/http_auth_handler_digest.cc
index 7c5526c..e8cb819 100644
--- a/net/http/http_auth_handler_digest.cc
+++ b/net/http/http_auth_handler_digest.cc
@@ -74,46 +74,60 @@
   return nonce_;
 }
 
-// static
-std::string HttpAuthHandlerDigest::QopToString(QualityOfProtection qop) {
-  switch (qop) {
-    case QOP_UNSPECIFIED:
-      return "";
-    case QOP_AUTH:
-      return "auth";
-    default:
-      NOTREACHED();
-      return "";
+HttpAuthHandlerDigest::Factory::Factory()
+    : nonce_generator_(new DynamicNonceGenerator()) {
+}
+
+HttpAuthHandlerDigest::Factory::~Factory() {
+}
+
+void HttpAuthHandlerDigest::Factory::set_nonce_generator(
+    const NonceGenerator* nonce_generator) {
+  nonce_generator_.reset(nonce_generator);
+}
+
+int HttpAuthHandlerDigest::Factory::CreateAuthHandler(
+    HttpAuth::ChallengeTokenizer* challenge,
+    HttpAuth::Target target,
+    const GURL& origin,
+    CreateReason reason,
+    int digest_nonce_count,
+    const BoundNetLog& net_log,
+    scoped_ptr<HttpAuthHandler>* handler) {
+  // TODO(cbentzel): Move towards model of parsing in the factory
+  //                 method and only constructing when valid.
+  scoped_ptr<HttpAuthHandler> tmp_handler(
+      new HttpAuthHandlerDigest(digest_nonce_count, nonce_generator_.get()));
+  if (!tmp_handler->InitFromChallenge(challenge, target, origin, net_log))
+    return ERR_INVALID_RESPONSE;
+  handler->swap(tmp_handler);
+  return OK;
+}
+
+HttpAuth::AuthorizationResult HttpAuthHandlerDigest::HandleAnotherChallenge(
+    HttpAuth::ChallengeTokenizer* challenge) {
+  // Even though Digest is not connection based, a "second round" is parsed
+  // to differentiate between stale and rejected responses.
+  // Note that the state of the current handler is not mutated - this way if
+  // there is a rejection the realm hasn't changed.
+  if (!LowerCaseEqualsASCII(challenge->scheme(), "digest"))
+    return HttpAuth::AUTHORIZATION_RESULT_INVALID;
+
+  HttpUtil::NameValuePairsIterator parameters = challenge->param_pairs();
+
+  // Try to find the "stale" value.
+  while (parameters.GetNext()) {
+    if (!LowerCaseEqualsASCII(parameters.name(), "stale"))
+      continue;
+    if (LowerCaseEqualsASCII(parameters.value(), "true"))
+      return HttpAuth::AUTHORIZATION_RESULT_STALE;
   }
+
+  return HttpAuth::AUTHORIZATION_RESULT_REJECT;
 }
 
-// static
-std::string HttpAuthHandlerDigest::AlgorithmToString(
-    DigestAlgorithm algorithm) {
-  switch (algorithm) {
-    case ALGORITHM_UNSPECIFIED:
-      return "";
-    case ALGORITHM_MD5:
-      return "MD5";
-    case ALGORITHM_MD5_SESS:
-      return "MD5-sess";
-    default:
-      NOTREACHED();
-      return "";
-  }
-}
-
-HttpAuthHandlerDigest::HttpAuthHandlerDigest(
-    int nonce_count, const NonceGenerator* nonce_generator)
-    : stale_(false),
-      algorithm_(ALGORITHM_UNSPECIFIED),
-      qop_(QOP_UNSPECIFIED),
-      nonce_count_(nonce_count),
-      nonce_generator_(nonce_generator) {
-  DCHECK(nonce_generator_);
-}
-
-HttpAuthHandlerDigest::~HttpAuthHandlerDigest() {
+bool HttpAuthHandlerDigest::Init(HttpAuth::ChallengeTokenizer* challenge) {
+  return ParseChallenge(challenge);
 }
 
 int HttpAuthHandlerDigest::GenerateAuthTokenImpl(
@@ -138,112 +152,17 @@
   return OK;
 }
 
-void HttpAuthHandlerDigest::GetRequestMethodAndPath(
-    const HttpRequestInfo* request,
-    std::string* method,
-    std::string* path) const {
-  DCHECK(request);
-
-  const GURL& url = request->url;
-
-  if (target_ == HttpAuth::AUTH_PROXY && url.SchemeIs("https")) {
-    *method = "CONNECT";
-    *path = GetHostAndPort(url);
-  } else {
-    *method = request->method;
-    *path = HttpUtil::PathForRequest(url);
-  }
+HttpAuthHandlerDigest::HttpAuthHandlerDigest(
+    int nonce_count, const NonceGenerator* nonce_generator)
+    : stale_(false),
+      algorithm_(ALGORITHM_UNSPECIFIED),
+      qop_(QOP_UNSPECIFIED),
+      nonce_count_(nonce_count),
+      nonce_generator_(nonce_generator) {
+  DCHECK(nonce_generator_);
 }
 
-std::string HttpAuthHandlerDigest::AssembleResponseDigest(
-    const std::string& method,
-    const std::string& path,
-    const string16& username,
-    const string16& password,
-    const std::string& cnonce,
-    const std::string& nc) const {
-  // ha1 = MD5(A1)
-  // TODO(eroman): is this the right encoding?
-  std::string ha1 = MD5String(UTF16ToUTF8(username) + ":" + realm_ + ":" +
-                              UTF16ToUTF8(password));
-  if (algorithm_ == HttpAuthHandlerDigest::ALGORITHM_MD5_SESS)
-    ha1 = MD5String(ha1 + ":" + nonce_ + ":" + cnonce);
-
-  // ha2 = MD5(A2)
-  // TODO(eroman): need to add MD5(req-entity-body) for qop=auth-int.
-  std::string ha2 = MD5String(method + ":" + path);
-
-  std::string nc_part;
-  if (qop_ != HttpAuthHandlerDigest::QOP_UNSPECIFIED) {
-    nc_part = nc + ":" + cnonce + ":" + QopToString(qop_) + ":";
-  }
-
-  return MD5String(ha1 + ":" + nonce_ + ":" + nc_part + ha2);
-}
-
-std::string HttpAuthHandlerDigest::AssembleCredentials(
-    const std::string& method,
-    const std::string& path,
-    const string16& username,
-    const string16& password,
-    const std::string& cnonce,
-    int nonce_count) const {
-  // the nonce-count is an 8 digit hex string.
-  std::string nc = base::StringPrintf("%08x", nonce_count);
-
-  // TODO(eroman): is this the right encoding?
-  std::string authorization = (std::string("Digest username=") +
-                               HttpUtil::Quote(UTF16ToUTF8(username)));
-  authorization += ", realm=" + HttpUtil::Quote(realm_);
-  authorization += ", nonce=" + HttpUtil::Quote(nonce_);
-  authorization += ", uri=" + HttpUtil::Quote(path);
-
-  if (algorithm_ != ALGORITHM_UNSPECIFIED) {
-    authorization += ", algorithm=" + AlgorithmToString(algorithm_);
-  }
-  std::string response = AssembleResponseDigest(method, path, username,
-                                                password, cnonce, nc);
-  // No need to call HttpUtil::Quote() as the response digest cannot contain
-  // any characters needing to be escaped.
-  authorization += ", response=\"" + response + "\"";
-
-  if (!opaque_.empty()) {
-    authorization += ", opaque=" + HttpUtil::Quote(opaque_);
-  }
-  if (qop_ != QOP_UNSPECIFIED) {
-    // TODO(eroman): Supposedly IIS server requires quotes surrounding qop.
-    authorization += ", qop=" + QopToString(qop_);
-    authorization += ", nc=" + nc;
-    authorization += ", cnonce=" + HttpUtil::Quote(cnonce);
-  }
-
-  return authorization;
-}
-
-bool HttpAuthHandlerDigest::Init(HttpAuth::ChallengeTokenizer* challenge) {
-  return ParseChallenge(challenge);
-}
-
-HttpAuth::AuthorizationResult HttpAuthHandlerDigest::HandleAnotherChallenge(
-    HttpAuth::ChallengeTokenizer* challenge) {
-  // Even though Digest is not connection based, a "second round" is parsed
-  // to differentiate between stale and rejected responses.
-  // Note that the state of the current handler is not mutated - this way if
-  // there is a rejection the realm hasn't changed.
-  if (!LowerCaseEqualsASCII(challenge->scheme(), "digest"))
-    return HttpAuth::AUTHORIZATION_RESULT_INVALID;
-
-  HttpUtil::NameValuePairsIterator parameters = challenge->param_pairs();
-
-  // Try to find the "stale" value.
-  while (parameters.GetNext()) {
-    if (!LowerCaseEqualsASCII(parameters.name(), "stale"))
-      continue;
-    if (LowerCaseEqualsASCII(parameters.value(), "true"))
-      return HttpAuth::AUTHORIZATION_RESULT_STALE;
-  }
-
-  return HttpAuth::AUTHORIZATION_RESULT_REJECT;
+HttpAuthHandlerDigest::~HttpAuthHandlerDigest() {
 }
 
 // The digest challenge header looks like:
@@ -342,34 +261,115 @@
   return true;
 }
 
-HttpAuthHandlerDigest::Factory::Factory()
-    : nonce_generator_(new DynamicNonceGenerator()) {
+// static
+std::string HttpAuthHandlerDigest::QopToString(QualityOfProtection qop) {
+  switch (qop) {
+    case QOP_UNSPECIFIED:
+      return "";
+    case QOP_AUTH:
+      return "auth";
+    default:
+      NOTREACHED();
+      return "";
+  }
 }
 
-HttpAuthHandlerDigest::Factory::~Factory() {
+// static
+std::string HttpAuthHandlerDigest::AlgorithmToString(
+    DigestAlgorithm algorithm) {
+  switch (algorithm) {
+    case ALGORITHM_UNSPECIFIED:
+      return "";
+    case ALGORITHM_MD5:
+      return "MD5";
+    case ALGORITHM_MD5_SESS:
+      return "MD5-sess";
+    default:
+      NOTREACHED();
+      return "";
+  }
 }
 
-void HttpAuthHandlerDigest::Factory::set_nonce_generator(
-    const NonceGenerator* nonce_generator) {
-  nonce_generator_.reset(nonce_generator);
+void HttpAuthHandlerDigest::GetRequestMethodAndPath(
+    const HttpRequestInfo* request,
+    std::string* method,
+    std::string* path) const {
+  DCHECK(request);
+
+  const GURL& url = request->url;
+
+  if (target_ == HttpAuth::AUTH_PROXY && url.SchemeIs("https")) {
+    *method = "CONNECT";
+    *path = GetHostAndPort(url);
+  } else {
+    *method = request->method;
+    *path = HttpUtil::PathForRequest(url);
+  }
 }
 
-int HttpAuthHandlerDigest::Factory::CreateAuthHandler(
-    HttpAuth::ChallengeTokenizer* challenge,
-    HttpAuth::Target target,
-    const GURL& origin,
-    CreateReason reason,
-    int digest_nonce_count,
-    const BoundNetLog& net_log,
-    scoped_ptr<HttpAuthHandler>* handler) {
-  // TODO(cbentzel): Move towards model of parsing in the factory
-  //                 method and only constructing when valid.
-  scoped_ptr<HttpAuthHandler> tmp_handler(
-      new HttpAuthHandlerDigest(digest_nonce_count, nonce_generator_.get()));
-  if (!tmp_handler->InitFromChallenge(challenge, target, origin, net_log))
-    return ERR_INVALID_RESPONSE;
-  handler->swap(tmp_handler);
-  return OK;
+std::string HttpAuthHandlerDigest::AssembleResponseDigest(
+    const std::string& method,
+    const std::string& path,
+    const string16& username,
+    const string16& password,
+    const std::string& cnonce,
+    const std::string& nc) const {
+  // ha1 = MD5(A1)
+  // TODO(eroman): is this the right encoding?
+  std::string ha1 = MD5String(UTF16ToUTF8(username) + ":" + realm_ + ":" +
+                              UTF16ToUTF8(password));
+  if (algorithm_ == HttpAuthHandlerDigest::ALGORITHM_MD5_SESS)
+    ha1 = MD5String(ha1 + ":" + nonce_ + ":" + cnonce);
+
+  // ha2 = MD5(A2)
+  // TODO(eroman): need to add MD5(req-entity-body) for qop=auth-int.
+  std::string ha2 = MD5String(method + ":" + path);
+
+  std::string nc_part;
+  if (qop_ != HttpAuthHandlerDigest::QOP_UNSPECIFIED) {
+    nc_part = nc + ":" + cnonce + ":" + QopToString(qop_) + ":";
+  }
+
+  return MD5String(ha1 + ":" + nonce_ + ":" + nc_part + ha2);
+}
+
+std::string HttpAuthHandlerDigest::AssembleCredentials(
+    const std::string& method,
+    const std::string& path,
+    const string16& username,
+    const string16& password,
+    const std::string& cnonce,
+    int nonce_count) const {
+  // the nonce-count is an 8 digit hex string.
+  std::string nc = base::StringPrintf("%08x", nonce_count);
+
+  // TODO(eroman): is this the right encoding?
+  std::string authorization = (std::string("Digest username=") +
+                               HttpUtil::Quote(UTF16ToUTF8(username)));
+  authorization += ", realm=" + HttpUtil::Quote(realm_);
+  authorization += ", nonce=" + HttpUtil::Quote(nonce_);
+  authorization += ", uri=" + HttpUtil::Quote(path);
+
+  if (algorithm_ != ALGORITHM_UNSPECIFIED) {
+    authorization += ", algorithm=" + AlgorithmToString(algorithm_);
+  }
+  std::string response = AssembleResponseDigest(method, path, username,
+                                                password, cnonce, nc);
+  // No need to call HttpUtil::Quote() as the response digest cannot contain
+  // any characters needing to be escaped.
+  authorization += ", response=\"" + response + "\"";
+
+  if (!opaque_.empty()) {
+    authorization += ", opaque=" + HttpUtil::Quote(opaque_);
+  }
+  if (qop_ != QOP_UNSPECIFIED) {
+    // TODO(eroman): Supposedly IIS server requires quotes surrounding qop.
+    authorization += ", qop=" + QopToString(qop_);
+    authorization += ", nc=" + nc;
+    authorization += ", cnonce=" + HttpUtil::Quote(cnonce);
+  }
+
+  return authorization;
 }
 
 }  // namespace net
diff --git a/net/http/http_auth_handler_digest.h b/net/http/http_auth_handler_digest.h
index c319f5dc..fca77e451 100644
--- a/net/http/http_auth_handler_digest.h
+++ b/net/http/http_auth_handler_digest.h
@@ -62,6 +62,9 @@
     Factory();
     virtual ~Factory();
 
+    // This factory owns the passed in |nonce_generator|.
+    void set_nonce_generator(const NonceGenerator* nonce_generator);
+
     virtual int CreateAuthHandler(HttpAuth::ChallengeTokenizer* challenge,
                                   HttpAuth::Target target,
                                   const GURL& origin,
@@ -70,9 +73,6 @@
                                   const BoundNetLog& net_log,
                                   scoped_ptr<HttpAuthHandler>* handler);
 
-    // This factory owns the passed in |nonce_generator|.
-    void set_nonce_generator(const NonceGenerator* nonce_generator);
-
    private:
     scoped_ptr<const NonceGenerator> nonce_generator_;
   };
diff --git a/net/http/http_auth_handler_mock.cc b/net/http/http_auth_handler_mock.cc
index b4e2268e..aad1bd18 100644
--- a/net/http/http_auth_handler_mock.cc
+++ b/net/http/http_auth_handler_mock.cc
@@ -71,13 +71,6 @@
   generate_rv_ = rv;
 }
 
-bool HttpAuthHandlerMock::Init(HttpAuth::ChallengeTokenizer* challenge) {
-  auth_scheme_ = HttpAuth::AUTH_SCHEME_MOCK;
-  score_ = 1;
-  properties_ = connection_based_ ? IS_CONNECTION_BASED : 0;
-  return true;
-}
-
 HttpAuth::AuthorizationResult HttpAuthHandlerMock::HandleAnotherChallenge(
     HttpAuth::ChallengeTokenizer* challenge) {
   if (!is_connection_based())
@@ -87,6 +80,17 @@
   return HttpAuth::AUTHORIZATION_RESULT_ACCEPT;
 }
 
+bool HttpAuthHandlerMock::NeedsIdentity() {
+  return first_round_;
+}
+
+bool HttpAuthHandlerMock::Init(HttpAuth::ChallengeTokenizer* challenge) {
+  auth_scheme_ = HttpAuth::AUTH_SCHEME_MOCK;
+  score_ = 1;
+  properties_ = connection_based_ ? IS_CONNECTION_BASED : 0;
+  return true;
+}
+
 int HttpAuthHandlerMock::GenerateAuthTokenImpl(const string16* username,
                                                const string16* password,
                                                const HttpRequestInfo* request,
diff --git a/net/http/http_auth_handler_mock.h b/net/http/http_auth_handler_mock.h
index bef8b2b8..473ca2e1 100644
--- a/net/http/http_auth_handler_mock.h
+++ b/net/http/http_auth_handler_mock.h
@@ -29,32 +29,6 @@
     RESOLVE_TESTED,
   };
 
-  HttpAuthHandlerMock();
-
-  virtual ~HttpAuthHandlerMock();
-
-  void SetResolveExpectation(Resolve resolve);
-
-  virtual bool NeedsCanonicalName();
-
-  virtual int ResolveCanonicalName(HostResolver* host_resolver,
-                                   CompletionCallback* callback);
-
-  virtual bool NeedsIdentity() { return first_round_; }
-
-  void SetGenerateExpectation(bool async, int rv);
-
-  void set_connection_based(bool connection_based) {
-    connection_based_ = connection_based;
-  }
-
-  const GURL& request_url() const {
-    return request_url_;
-  }
-
-  HttpAuth::AuthorizationResult HandleAnotherChallenge(
-      HttpAuth::ChallengeTokenizer* challenge);
-
   // The Factory class simply returns the same handler each time
   // CreateAuthHandler is called.
   class Factory : public HttpAuthHandlerFactory {
@@ -68,6 +42,7 @@
       do_init_from_challenge_ = do_init_from_challenge;
     }
 
+    // HttpAuthHandlerFactory:
     virtual int CreateAuthHandler(HttpAuth::ChallengeTokenizer* challenge,
                                   HttpAuth::Target target,
                                   const GURL& origin,
@@ -81,6 +56,33 @@
     bool do_init_from_challenge_;
   };
 
+  HttpAuthHandlerMock();
+
+  virtual ~HttpAuthHandlerMock();
+
+  void SetResolveExpectation(Resolve resolve);
+
+  virtual bool NeedsCanonicalName();
+
+  virtual int ResolveCanonicalName(HostResolver* host_resolver,
+                                   CompletionCallback* callback);
+
+
+  void SetGenerateExpectation(bool async, int rv);
+
+  void set_connection_based(bool connection_based) {
+    connection_based_ = connection_based;
+  }
+
+  const GURL& request_url() const {
+    return request_url_;
+  }
+
+  // HttpAuthHandler:
+  virtual HttpAuth::AuthorizationResult HandleAnotherChallenge(
+      HttpAuth::ChallengeTokenizer* challenge);
+  virtual bool NeedsIdentity();
+
  protected:
   virtual bool Init(HttpAuth::ChallengeTokenizer* challenge);
 
diff --git a/net/http/http_auth_handler_negotiate.cc b/net/http/http_auth_handler_negotiate.cc
index cedd2823..a96902d 100644
--- a/net/http/http_auth_handler_negotiate.cc
+++ b/net/http/http_auth_handler_negotiate.cc
@@ -16,6 +16,68 @@
 
 namespace net {
 
+HttpAuthHandlerNegotiate::Factory::Factory()
+    : disable_cname_lookup_(false),
+      use_port_(false),
+#if defined(OS_WIN)
+      max_token_length_(0),
+      first_creation_(true),
+      is_unsupported_(false),
+#endif
+      auth_library_(NULL) {
+}
+
+HttpAuthHandlerNegotiate::Factory::~Factory() {
+}
+
+void HttpAuthHandlerNegotiate::Factory::set_host_resolver(
+    HostResolver* resolver) {
+  resolver_ = resolver;
+}
+
+int HttpAuthHandlerNegotiate::Factory::CreateAuthHandler(
+    HttpAuth::ChallengeTokenizer* challenge,
+    HttpAuth::Target target,
+    const GURL& origin,
+    CreateReason reason,
+    int digest_nonce_count,
+    const BoundNetLog& net_log,
+    scoped_ptr<HttpAuthHandler>* handler) {
+#if defined(OS_WIN)
+  if (is_unsupported_ || reason == CREATE_PREEMPTIVE)
+    return ERR_UNSUPPORTED_AUTH_SCHEME;
+  if (max_token_length_ == 0) {
+    int rv = DetermineMaxTokenLength(auth_library_.get(), NEGOSSP_NAME,
+                                     &max_token_length_);
+    if (rv == ERR_UNSUPPORTED_AUTH_SCHEME)
+      is_unsupported_ = true;
+    if (rv != OK)
+      return rv;
+  }
+  // TODO(cbentzel): Move towards model of parsing in the factory
+  //                 method and only constructing when valid.
+  scoped_ptr<HttpAuthHandler> tmp_handler(
+      new HttpAuthHandlerNegotiate(auth_library_.get(), max_token_length_,
+                                   url_security_manager(), resolver_,
+                                   disable_cname_lookup_, use_port_));
+  if (!tmp_handler->InitFromChallenge(challenge, target, origin, net_log))
+    return ERR_INVALID_RESPONSE;
+  handler->swap(tmp_handler);
+  return OK;
+#elif defined(OS_POSIX)
+  // TODO(ahendrickson): Move towards model of parsing in the factory
+  //                     method and only constructing when valid.
+  scoped_ptr<HttpAuthHandler> tmp_handler(
+      new HttpAuthHandlerNegotiate(auth_library_.get(), url_security_manager(),
+                                   resolver_, disable_cname_lookup_,
+                                   use_port_));
+  if (!tmp_handler->InitFromChallenge(challenge, target, origin, net_log))
+    return ERR_INVALID_RESPONSE;
+  handler->swap(tmp_handler);
+  return OK;
+#endif
+}
+
 HttpAuthHandlerNegotiate::HttpAuthHandlerNegotiate(
     AuthLibrary* auth_library,
 #if defined(OS_WIN)
@@ -46,88 +108,6 @@
 HttpAuthHandlerNegotiate::~HttpAuthHandlerNegotiate() {
 }
 
-int HttpAuthHandlerNegotiate::GenerateAuthTokenImpl(
-    const string16* username,
-    const string16* password,
-    const HttpRequestInfo* request,
-    CompletionCallback* callback,
-    std::string* auth_token) {
-  DCHECK(user_callback_ == NULL);
-  DCHECK((username == NULL) == (password == NULL));
-  DCHECK(auth_token_ == NULL);
-  auth_token_ = auth_token;
-  if (already_called_) {
-    DCHECK((!has_username_and_password_ && username == NULL) ||
-           (has_username_and_password_ && *username == username_ &&
-            *password == password_));
-    next_state_ = STATE_GENERATE_AUTH_TOKEN;
-  } else {
-    already_called_ = true;
-    if (username) {
-      has_username_and_password_ = true;
-      username_ = *username;
-      password_ = *password;
-    }
-    next_state_ = STATE_RESOLVE_CANONICAL_NAME;
-  }
-  int rv = DoLoop(OK);
-  if (rv == ERR_IO_PENDING)
-    user_callback_ = callback;
-  return rv;
-}
-
-// The Negotiate challenge header looks like:
-//   WWW-Authenticate: NEGOTIATE auth-data
-bool HttpAuthHandlerNegotiate::Init(HttpAuth::ChallengeTokenizer* challenge) {
-#if defined(OS_POSIX)
-  if (!auth_system_.Init()) {
-    VLOG(1) << "can't initialize GSSAPI library";
-    return false;
-  }
-  // GSSAPI does not provide a way to enter username/password to
-  // obtain a TGT. If the default credentials are not allowed for
-  // a particular site (based on whitelist), fall back to a
-  // different scheme.
-  if (!AllowsDefaultCredentials())
-    return false;
-#endif
-  if (CanDelegate())
-    auth_system_.Delegate();
-  auth_scheme_ = HttpAuth::AUTH_SCHEME_NEGOTIATE;
-  score_ = 4;
-  properties_ = ENCRYPTS_IDENTITY | IS_CONNECTION_BASED;
-  HttpAuth::AuthorizationResult auth_result =
-      auth_system_.ParseChallenge(challenge);
-  return (auth_result == HttpAuth::AUTHORIZATION_RESULT_ACCEPT);
-}
-
-HttpAuth::AuthorizationResult HttpAuthHandlerNegotiate::HandleAnotherChallenge(
-    HttpAuth::ChallengeTokenizer* challenge) {
-  return auth_system_.ParseChallenge(challenge);
-}
-
-// Require identity on first pass instead of second.
-bool HttpAuthHandlerNegotiate::NeedsIdentity() {
-  return auth_system_.NeedsIdentity();
-}
-
-bool HttpAuthHandlerNegotiate::AllowsDefaultCredentials() {
-  if (target_ == HttpAuth::AUTH_PROXY)
-    return true;
-  if (!url_security_manager_)
-    return false;
-  return url_security_manager_->CanUseDefaultCredentials(origin_);
-}
-
-bool HttpAuthHandlerNegotiate::CanDelegate() const {
-  // TODO(cbentzel): Should delegation be allowed on proxies?
-  if (target_ == HttpAuth::AUTH_PROXY)
-    return false;
-  if (!url_security_manager_)
-    return false;
-  return url_security_manager_->CanDelegate(origin_);
-}
-
 std::wstring HttpAuthHandlerNegotiate::CreateSPN(
     const AddressList& address_list, const GURL& origin) {
   // Kerberos Web Server SPNs are in the form HTTP/<host>:<port> through SSPI,
@@ -177,6 +157,93 @@
   }
 }
 
+HttpAuth::AuthorizationResult HttpAuthHandlerNegotiate::HandleAnotherChallenge(
+    HttpAuth::ChallengeTokenizer* challenge) {
+  return auth_system_.ParseChallenge(challenge);
+}
+
+// Require identity on first pass instead of second.
+bool HttpAuthHandlerNegotiate::NeedsIdentity() {
+  return auth_system_.NeedsIdentity();
+}
+
+bool HttpAuthHandlerNegotiate::AllowsDefaultCredentials() {
+  if (target_ == HttpAuth::AUTH_PROXY)
+    return true;
+  if (!url_security_manager_)
+    return false;
+  return url_security_manager_->CanUseDefaultCredentials(origin_);
+}
+
+// The Negotiate challenge header looks like:
+//   WWW-Authenticate: NEGOTIATE auth-data
+bool HttpAuthHandlerNegotiate::Init(HttpAuth::ChallengeTokenizer* challenge) {
+#if defined(OS_POSIX)
+  if (!auth_system_.Init()) {
+    VLOG(1) << "can't initialize GSSAPI library";
+    return false;
+  }
+  // GSSAPI does not provide a way to enter username/password to
+  // obtain a TGT. If the default credentials are not allowed for
+  // a particular site (based on whitelist), fall back to a
+  // different scheme.
+  if (!AllowsDefaultCredentials())
+    return false;
+#endif
+  if (CanDelegate())
+    auth_system_.Delegate();
+  auth_scheme_ = HttpAuth::AUTH_SCHEME_NEGOTIATE;
+  score_ = 4;
+  properties_ = ENCRYPTS_IDENTITY | IS_CONNECTION_BASED;
+  HttpAuth::AuthorizationResult auth_result =
+      auth_system_.ParseChallenge(challenge);
+  return (auth_result == HttpAuth::AUTHORIZATION_RESULT_ACCEPT);
+}
+
+int HttpAuthHandlerNegotiate::GenerateAuthTokenImpl(
+    const string16* username,
+    const string16* password,
+    const HttpRequestInfo* request,
+    CompletionCallback* callback,
+    std::string* auth_token) {
+  DCHECK(user_callback_ == NULL);
+  DCHECK((username == NULL) == (password == NULL));
+  DCHECK(auth_token_ == NULL);
+  auth_token_ = auth_token;
+  if (already_called_) {
+    DCHECK((!has_username_and_password_ && username == NULL) ||
+           (has_username_and_password_ && *username == username_ &&
+            *password == password_));
+    next_state_ = STATE_GENERATE_AUTH_TOKEN;
+  } else {
+    already_called_ = true;
+    if (username) {
+      has_username_and_password_ = true;
+      username_ = *username;
+      password_ = *password;
+    }
+    next_state_ = STATE_RESOLVE_CANONICAL_NAME;
+  }
+  int rv = DoLoop(OK);
+  if (rv == ERR_IO_PENDING)
+    user_callback_ = callback;
+  return rv;
+}
+
+void HttpAuthHandlerNegotiate::OnIOComplete(int result) {
+  int rv = DoLoop(result);
+  if (rv != ERR_IO_PENDING)
+    DoCallback(rv);
+}
+
+void HttpAuthHandlerNegotiate::DoCallback(int rv) {
+  DCHECK(rv != ERR_IO_PENDING);
+  DCHECK(user_callback_);
+  CompletionCallback* callback = user_callback_;
+  user_callback_ = NULL;
+  callback->Run(rv);
+}
+
 int HttpAuthHandlerNegotiate::DoLoop(int result) {
   DCHECK(next_state_ != STATE_NONE);
 
@@ -253,80 +320,13 @@
   return rv;
 }
 
-void HttpAuthHandlerNegotiate::OnIOComplete(int result) {
-  int rv = DoLoop(result);
-  if (rv != ERR_IO_PENDING)
-    DoCallback(rv);
-}
-
-void HttpAuthHandlerNegotiate::DoCallback(int rv) {
-  DCHECK(rv != ERR_IO_PENDING);
-  DCHECK(user_callback_);
-  CompletionCallback* callback = user_callback_;
-  user_callback_ = NULL;
-  callback->Run(rv);
-}
-
-HttpAuthHandlerNegotiate::Factory::Factory()
-    : disable_cname_lookup_(false),
-      use_port_(false),
-#if defined(OS_WIN)
-      max_token_length_(0),
-      first_creation_(true),
-      is_unsupported_(false),
-#endif
-      auth_library_(NULL) {
-}
-
-HttpAuthHandlerNegotiate::Factory::~Factory() {
-}
-
-void HttpAuthHandlerNegotiate::Factory::set_host_resolver(
-    HostResolver* resolver) {
-  resolver_ = resolver;
-}
-
-int HttpAuthHandlerNegotiate::Factory::CreateAuthHandler(
-    HttpAuth::ChallengeTokenizer* challenge,
-    HttpAuth::Target target,
-    const GURL& origin,
-    CreateReason reason,
-    int digest_nonce_count,
-    const BoundNetLog& net_log,
-    scoped_ptr<HttpAuthHandler>* handler) {
-#if defined(OS_WIN)
-  if (is_unsupported_ || reason == CREATE_PREEMPTIVE)
-    return ERR_UNSUPPORTED_AUTH_SCHEME;
-  if (max_token_length_ == 0) {
-    int rv = DetermineMaxTokenLength(auth_library_.get(), NEGOSSP_NAME,
-                                     &max_token_length_);
-    if (rv == ERR_UNSUPPORTED_AUTH_SCHEME)
-      is_unsupported_ = true;
-    if (rv != OK)
-      return rv;
-  }
-  // TODO(cbentzel): Move towards model of parsing in the factory
-  //                 method and only constructing when valid.
-  scoped_ptr<HttpAuthHandler> tmp_handler(
-      new HttpAuthHandlerNegotiate(auth_library_.get(), max_token_length_,
-                                   url_security_manager(), resolver_,
-                                   disable_cname_lookup_, use_port_));
-  if (!tmp_handler->InitFromChallenge(challenge, target, origin, net_log))
-    return ERR_INVALID_RESPONSE;
-  handler->swap(tmp_handler);
-  return OK;
-#elif defined(OS_POSIX)
-  // TODO(ahendrickson): Move towards model of parsing in the factory
-  //                     method and only constructing when valid.
-  scoped_ptr<HttpAuthHandler> tmp_handler(
-      new HttpAuthHandlerNegotiate(auth_library_.get(), url_security_manager(),
-                                   resolver_, disable_cname_lookup_,
-                                   use_port_));
-  if (!tmp_handler->InitFromChallenge(challenge, target, origin, net_log))
-    return ERR_INVALID_RESPONSE;
-  handler->swap(tmp_handler);
-  return OK;
-#endif
+bool HttpAuthHandlerNegotiate::CanDelegate() const {
+  // TODO(cbentzel): Should delegation be allowed on proxies?
+  if (target_ == HttpAuth::AUTH_PROXY)
+    return false;
+  if (!url_security_manager_)
+    return false;
+  return url_security_manager_->CanDelegate(origin_);
 }
 
 }  // namespace net
diff --git a/net/http/http_auth_handler_negotiate.h b/net/http/http_auth_handler_negotiate.h
index a19d182..de2a6e6 100644
--- a/net/http/http_auth_handler_negotiate.h
+++ b/net/http/http_auth_handler_negotiate.h
@@ -64,6 +64,12 @@
 
     void set_host_resolver(HostResolver* host_resolver);
 
+    // Sets the system library to use, thereby assuming ownership of
+    // |auth_library|.
+    void set_library(AuthLibrary* auth_library) {
+      auth_library_.reset(auth_library);
+    }
+
     virtual int CreateAuthHandler(HttpAuth::ChallengeTokenizer* challenge,
                                   HttpAuth::Target target,
                                   const GURL& origin,
@@ -72,12 +78,6 @@
                                   const BoundNetLog& net_log,
                                   scoped_ptr<HttpAuthHandler>* handler);
 
-    // Sets the system library to use, thereby assuming ownership of
-    // |auth_library|.
-    void set_library(AuthLibrary* auth_library) {
-      auth_library_.reset(auth_library);
-    }
-
    private:
     bool disable_cname_lookup_;
     bool use_port_;
@@ -101,17 +101,16 @@
 
   virtual ~HttpAuthHandlerNegotiate();
 
-  virtual bool NeedsIdentity();
-
-  virtual bool AllowsDefaultCredentials();
-
-  virtual HttpAuth::AuthorizationResult HandleAnotherChallenge(
-      HttpAuth::ChallengeTokenizer* challenge);
-
   // These are public for unit tests
   std::wstring CreateSPN(const AddressList& address_list, const GURL& orign);
   const std::wstring& spn() const { return spn_; }
 
+  // HttpAuthHandler:
+  virtual HttpAuth::AuthorizationResult HandleAnotherChallenge(
+      HttpAuth::ChallengeTokenizer* challenge);
+  virtual bool NeedsIdentity();
+  virtual bool AllowsDefaultCredentials();
+
  protected:
   virtual bool Init(HttpAuth::ChallengeTokenizer* challenge);
 
diff --git a/net/http/http_auth_handler_ntlm.cc b/net/http/http_auth_handler_ntlm.cc
index c3e44ba..5090918 100644
--- a/net/http/http_auth_handler_ntlm.cc
+++ b/net/http/http_auth_handler_ntlm.cc
@@ -15,6 +15,19 @@
 
 namespace net {
 
+HttpAuth::AuthorizationResult HttpAuthHandlerNTLM::HandleAnotherChallenge(
+    HttpAuth::ChallengeTokenizer* challenge) {
+  return ParseChallenge(challenge, false);
+}
+
+bool HttpAuthHandlerNTLM::Init(HttpAuth::ChallengeTokenizer* tok) {
+  auth_scheme_ = HttpAuth::AUTH_SCHEME_NTLM;
+  score_ = 3;
+  properties_ = ENCRYPTS_IDENTITY | IS_CONNECTION_BASED;
+
+  return ParseChallenge(tok, true) == HttpAuth::AUTHORIZATION_RESULT_ACCEPT;
+}
+
 int HttpAuthHandlerNTLM::GenerateAuthTokenImpl(
     const string16* username,
     const string16* password,
@@ -92,19 +105,6 @@
 #endif
 }
 
-bool HttpAuthHandlerNTLM::Init(HttpAuth::ChallengeTokenizer* tok) {
-  auth_scheme_ = HttpAuth::AUTH_SCHEME_NTLM;
-  score_ = 3;
-  properties_ = ENCRYPTS_IDENTITY | IS_CONNECTION_BASED;
-
-  return ParseChallenge(tok, true) == HttpAuth::AUTHORIZATION_RESULT_ACCEPT;
-}
-
-HttpAuth::AuthorizationResult HttpAuthHandlerNTLM::HandleAnotherChallenge(
-    HttpAuth::ChallengeTokenizer* challenge) {
-  return ParseChallenge(challenge, false);
-}
-
 // The NTLM challenge header looks like:
 //   WWW-Authenticate: NTLM auth-data
 HttpAuth::AuthorizationResult HttpAuthHandlerNTLM::ParseChallenge(
diff --git a/net/http/http_auth_handler_ntlm.h b/net/http/http_auth_handler_ntlm.h
index 831e43d..ae7c78bd 100644
--- a/net/http/http_auth_handler_ntlm.h
+++ b/net/http/http_auth_handler_ntlm.h
@@ -114,6 +114,10 @@
       HttpAuth::ChallengeTokenizer* challenge);
 
  protected:
+  // This function acquires a credentials handle in the SSPI implementation.
+  // It does nothing in the portable implementation.
+  int InitializeBeforeFirstChallenge();
+
   virtual bool Init(HttpAuth::ChallengeTokenizer* tok);
 
   virtual int GenerateAuthTokenImpl(const string16* username,
@@ -122,10 +126,6 @@
                                     CompletionCallback* callback,
                                     std::string* auth_token);
 
-  // This function acquires a credentials handle in the SSPI implementation.
-  // It does nothing in the portable implementation.
-  int InitializeBeforeFirstChallenge();
-
  private:
   ~HttpAuthHandlerNTLM();
 
diff --git a/net/http/http_auth_handler_ntlm_portable.cc b/net/http/http_auth_handler_ntlm_portable.cc
index d3abc98..2b06e58 100644
--- a/net/http/http_auth_handler_ntlm_portable.cc
+++ b/net/http/http_auth_handler_ntlm_portable.cc
@@ -643,12 +643,6 @@
 HttpAuthHandlerNTLM::HttpAuthHandlerNTLM() {
 }
 
-HttpAuthHandlerNTLM::~HttpAuthHandlerNTLM() {
-  // Wipe our copy of the password from memory, to reduce the chance of being
-  // written to the paging file on disk.
-  ZapString(&password_);
-}
-
 bool HttpAuthHandlerNTLM::NeedsIdentity() {
   return !auth_data_.empty();
 }
@@ -659,6 +653,16 @@
   return false;
 }
 
+int HttpAuthHandlerNTLM::InitializeBeforeFirstChallenge() {
+  return OK;
+}
+
+HttpAuthHandlerNTLM::~HttpAuthHandlerNTLM() {
+  // Wipe our copy of the password from memory, to reduce the chance of being
+  // written to the paging file on disk.
+  ZapString(&password_);
+}
+
 // static
 HttpAuthHandlerNTLM::GenerateRandomProc
 HttpAuthHandlerNTLM::SetGenerateRandomProc(
@@ -676,6 +680,12 @@
   return old_proc;
 }
 
+HttpAuthHandlerNTLM::Factory::Factory() {
+}
+
+HttpAuthHandlerNTLM::Factory::~Factory() {
+}
+
 int HttpAuthHandlerNTLM::GetNextToken(const void* in_token,
                                       uint32 in_token_len,
                                       void** out_token,
@@ -702,16 +712,6 @@
   return rv;
 }
 
-int HttpAuthHandlerNTLM::InitializeBeforeFirstChallenge() {
-  return OK;
-}
-
-HttpAuthHandlerNTLM::Factory::Factory() {
-}
-
-HttpAuthHandlerNTLM::Factory::~Factory() {
-}
-
 int HttpAuthHandlerNTLM::Factory::CreateAuthHandler(
     HttpAuth::ChallengeTokenizer* challenge,
     HttpAuth::Target target,
diff --git a/net/http/http_basic_stream.cc b/net/http/http_basic_stream.cc
index 061bb30f..3e69d7a4 100644
--- a/net/http/http_basic_stream.cc
+++ b/net/http/http_basic_stream.cc
@@ -25,6 +25,8 @@
       request_info_(NULL) {
 }
 
+HttpBasicStream::~HttpBasicStream() {}
+
 int HttpBasicStream::InitializeStream(const HttpRequestInfo* request_info,
                                       const BoundNetLog& net_log,
                                       CompletionCallback* callback) {
@@ -52,8 +54,6 @@
                               callback);
 }
 
-HttpBasicStream::~HttpBasicStream() {}
-
 uint64 HttpBasicStream::GetUploadProgress() const {
   return parser_->GetUploadProgress();
 }
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc
index b506edc..32386f0 100644
--- a/net/http/http_cache_transaction.cc
+++ b/net/http/http_cache_transaction.cc
@@ -163,6 +163,70 @@
   cache_.reset();
 }
 
+int HttpCache::Transaction::WriteMetadata(IOBuffer* buf, int buf_len,
+                                          CompletionCallback* callback) {
+  DCHECK(buf);
+  DCHECK_GT(buf_len, 0);
+  DCHECK(callback);
+  if (!cache_ || !entry_)
+    return ERR_UNEXPECTED;
+
+  // We don't need to track this operation for anything.
+  // It could be possible to check if there is something already written and
+  // avoid writing again (it should be the same, right?), but let's allow the
+  // caller to "update" the contents with something new.
+  return entry_->disk_entry->WriteData(kMetadataIndex, 0, buf, buf_len,
+                                       callback, true);
+}
+
+// Histogram data from the end of 2010 show the following distribution of
+// response headers:
+//
+//   Content-Length............... 87%
+//   Date......................... 98%
+//   Last-Modified................ 49%
+//   Etag......................... 19%
+//   Accept-Ranges: bytes......... 25%
+//   Accept-Ranges: none.......... 0.4%
+//   Strong Validator............. 50%
+//   Strong Validator + ranges.... 24%
+//   Strong Validator + CL........ 49%
+//
+bool HttpCache::Transaction::AddTruncatedFlag() {
+  DCHECK(mode_ & WRITE);
+
+  // Don't set the flag for sparse entries.
+  if (partial_.get() && !truncated_)
+    return true;
+
+  // Double check that there is something worth keeping.
+  if (!entry_->disk_entry->GetDataSize(kResponseContentIndex))
+    return false;
+
+  if (response_.headers->GetContentLength() <= 0 ||
+      response_.headers->HasHeaderValue("Accept-Ranges", "none") ||
+      !response_.headers->HasStrongValidators())
+    return false;
+
+  truncated_ = true;
+  target_state_ = STATE_NONE;
+  next_state_ = STATE_CACHE_WRITE_TRUNCATED_RESPONSE;
+  DoLoop(OK);
+  return true;
+}
+
+LoadState HttpCache::Transaction::GetWriterLoadState() const {
+  if (network_trans_.get())
+    return network_trans_->GetLoadState();
+  if (entry_ || !request_)
+    return LOAD_STATE_IDLE;
+  return LOAD_STATE_WAITING_FOR_CACHE;
+}
+
+const BoundNetLog& HttpCache::Transaction::net_log() const {
+  return net_log_;
+}
+
 int HttpCache::Transaction::Start(const HttpRequestInfo* request,
                                   CompletionCallback* callback,
                                   const BoundNetLog& net_log) {
@@ -338,70 +402,6 @@
   return final_upload_progress_;
 }
 
-int HttpCache::Transaction::WriteMetadata(IOBuffer* buf, int buf_len,
-                                          CompletionCallback* callback) {
-  DCHECK(buf);
-  DCHECK_GT(buf_len, 0);
-  DCHECK(callback);
-  if (!cache_ || !entry_)
-    return ERR_UNEXPECTED;
-
-  // We don't need to track this operation for anything.
-  // It could be possible to check if there is something already written and
-  // avoid writing again (it should be the same, right?), but let's allow the
-  // caller to "update" the contents with something new.
-  return entry_->disk_entry->WriteData(kMetadataIndex, 0, buf, buf_len,
-                                       callback, true);
-}
-
-// Histogram data from the end of 2010 show the following distribution of
-// response headers:
-//
-//   Content-Length............... 87%
-//   Date......................... 98%
-//   Last-Modified................ 49%
-//   Etag......................... 19%
-//   Accept-Ranges: bytes......... 25%
-//   Accept-Ranges: none.......... 0.4%
-//   Strong Validator............. 50%
-//   Strong Validator + ranges.... 24%
-//   Strong Validator + CL........ 49%
-//
-bool HttpCache::Transaction::AddTruncatedFlag() {
-  DCHECK(mode_ & WRITE);
-
-  // Don't set the flag for sparse entries.
-  if (partial_.get() && !truncated_)
-    return true;
-
-  // Double check that there is something worth keeping.
-  if (!entry_->disk_entry->GetDataSize(kResponseContentIndex))
-    return false;
-
-  if (response_.headers->GetContentLength() <= 0 ||
-      response_.headers->HasHeaderValue("Accept-Ranges", "none") ||
-      !response_.headers->HasStrongValidators())
-    return false;
-
-  truncated_ = true;
-  target_state_ = STATE_NONE;
-  next_state_ = STATE_CACHE_WRITE_TRUNCATED_RESPONSE;
-  DoLoop(OK);
-  return true;
-}
-
-LoadState HttpCache::Transaction::GetWriterLoadState() const {
-  if (network_trans_.get())
-    return network_trans_->GetLoadState();
-  if (entry_ || !request_)
-    return LOAD_STATE_IDLE;
-  return LOAD_STATE_WAITING_FOR_CACHE;
-}
-
-const BoundNetLog& HttpCache::Transaction::net_log() const {
-  return net_log_;
-}
-
 //-----------------------------------------------------------------------------
 
 void HttpCache::Transaction::DoCallback(int rv) {
diff --git a/net/http/http_cache_transaction.h b/net/http/http_cache_transaction.h
index 316c15b8..81160d5 100644
--- a/net/http/http_cache_transaction.h
+++ b/net/http/http_cache_transaction.h
@@ -28,25 +28,6 @@
 // factory.
 class HttpCache::Transaction : public HttpTransaction {
  public:
-  Transaction(HttpCache* cache);
-  virtual ~Transaction();
-
-  // HttpTransaction methods:
-  virtual int Start(const HttpRequestInfo*, CompletionCallback*,
-                    const BoundNetLog&);
-  virtual int RestartIgnoringLastError(CompletionCallback* callback);
-  virtual int RestartWithCertificate(X509Certificate* client_cert,
-                                     CompletionCallback* callback);
-  virtual int RestartWithAuth(const string16& username,
-                              const string16& password,
-                              CompletionCallback* callback);
-  virtual bool IsReadyToRestartForAuth();
-  virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
-  virtual void StopCaching();
-  virtual const HttpResponseInfo* GetResponseInfo() const;
-  virtual LoadState GetLoadState() const;
-  virtual uint64 GetUploadProgress(void) const;
-
   // The transaction has the following modes, which apply to how it may access
   // its cache entry.
   //
@@ -76,6 +57,9 @@
     UPDATE          = READ_META | WRITE,  // READ_WRITE & ~READ_DATA
   };
 
+  Transaction(HttpCache* cache);
+  virtual ~Transaction();
+
   Mode mode() const { return mode_; }
 
   const std::string& key() const { return cache_key_; }
@@ -112,6 +96,22 @@
 
   const BoundNetLog& net_log() const;
 
+  // HttpTransaction methods:
+  virtual int Start(const HttpRequestInfo*, CompletionCallback*,
+                    const BoundNetLog&);
+  virtual int RestartIgnoringLastError(CompletionCallback* callback);
+  virtual int RestartWithCertificate(X509Certificate* client_cert,
+                                     CompletionCallback* callback);
+  virtual int RestartWithAuth(const string16& username,
+                              const string16& password,
+                              CompletionCallback* callback);
+  virtual bool IsReadyToRestartForAuth();
+  virtual int Read(IOBuffer* buf, int buf_len, CompletionCallback* callback);
+  virtual void StopCaching();
+  virtual const HttpResponseInfo* GetResponseInfo() const;
+  virtual LoadState GetLoadState() const;
+  virtual uint64 GetUploadProgress(void) const;
+
  private:
   static const size_t kNumValidationHeaders = 2;
   // Helper struct to pair a header name with its value, for
diff --git a/net/http/http_network_layer.cc b/net/http/http_network_layer.cc
index 9a110342..975e75c 100644
--- a/net/http/http_network_layer.cc
+++ b/net/http/http_network_layer.cc
@@ -19,38 +19,6 @@
 
 //-----------------------------------------------------------------------------
 
-// static
-HttpTransactionFactory* HttpNetworkLayer::CreateFactory(
-    HostResolver* host_resolver,
-    CertVerifier* cert_verifier,
-    DnsRRResolver* dnsrr_resolver,
-    DnsCertProvenanceChecker* dns_cert_checker,
-    SSLHostInfoFactory* ssl_host_info_factory,
-    ProxyService* proxy_service,
-    SSLConfigService* ssl_config_service,
-    HttpAuthHandlerFactory* http_auth_handler_factory,
-    HttpNetworkDelegate* network_delegate,
-    NetLog* net_log) {
-  DCHECK(proxy_service);
-
-  return new HttpNetworkLayer(ClientSocketFactory::GetDefaultFactory(),
-                              host_resolver, cert_verifier, dnsrr_resolver,
-                              dns_cert_checker,
-                              ssl_host_info_factory, proxy_service,
-                              ssl_config_service, http_auth_handler_factory,
-                              network_delegate,
-                              net_log);
-}
-
-// static
-HttpTransactionFactory* HttpNetworkLayer::CreateFactory(
-    HttpNetworkSession* session) {
-  DCHECK(session);
-
-  return new HttpNetworkLayer(session);
-}
-
-//-----------------------------------------------------------------------------
 HttpNetworkLayer::HttpNetworkLayer(
     ClientSocketFactory* socket_factory,
     HostResolver* host_resolver,
@@ -132,56 +100,37 @@
 HttpNetworkLayer::~HttpNetworkLayer() {
 }
 
-int HttpNetworkLayer::CreateTransaction(scoped_ptr<HttpTransaction>* trans) {
-  if (suspended_)
-    return ERR_NETWORK_IO_SUSPENDED;
+//-----------------------------------------------------------------------------
 
-  trans->reset(new HttpNetworkTransaction(GetSession()));
-  return OK;
+// static
+HttpTransactionFactory* HttpNetworkLayer::CreateFactory(
+    HostResolver* host_resolver,
+    CertVerifier* cert_verifier,
+    DnsRRResolver* dnsrr_resolver,
+    DnsCertProvenanceChecker* dns_cert_checker,
+    SSLHostInfoFactory* ssl_host_info_factory,
+    ProxyService* proxy_service,
+    SSLConfigService* ssl_config_service,
+    HttpAuthHandlerFactory* http_auth_handler_factory,
+    HttpNetworkDelegate* network_delegate,
+    NetLog* net_log) {
+  DCHECK(proxy_service);
+
+  return new HttpNetworkLayer(ClientSocketFactory::GetDefaultFactory(),
+                              host_resolver, cert_verifier, dnsrr_resolver,
+                              dns_cert_checker,
+                              ssl_host_info_factory, proxy_service,
+                              ssl_config_service, http_auth_handler_factory,
+                              network_delegate,
+                              net_log);
 }
 
-HttpCache* HttpNetworkLayer::GetCache() {
-  return NULL;
-}
+// static
+HttpTransactionFactory* HttpNetworkLayer::CreateFactory(
+    HttpNetworkSession* session) {
+  DCHECK(session);
 
-void HttpNetworkLayer::Suspend(bool suspend) {
-  suspended_ = suspend;
-
-  if (suspend && session_)
-    session_->tcp_socket_pool()->CloseIdleSockets();
-}
-
-HttpNetworkSession* HttpNetworkLayer::GetSession() {
-  if (!session_) {
-    DCHECK(proxy_service_);
-    if (!spdy_session_pool_.get())
-      spdy_session_pool_.reset(new SpdySessionPool(ssl_config_service_));
-    session_ = new HttpNetworkSession(
-        host_resolver_,
-        cert_verifier_,
-        dnsrr_resolver_,
-        dns_cert_checker_,
-        ssl_host_info_factory_,
-        proxy_service_,
-        socket_factory_,
-        ssl_config_service_,
-        spdy_session_pool_.release(),
-        http_auth_handler_factory_,
-        network_delegate_,
-        net_log_);
-    // These were just temps for lazy-initializing HttpNetworkSession.
-    host_resolver_ = NULL;
-    cert_verifier_ = NULL;
-    dnsrr_resolver_ = NULL;
-    dns_cert_checker_ = NULL;
-    ssl_host_info_factory_ = NULL;
-    proxy_service_ = NULL;
-    socket_factory_ = NULL;
-    http_auth_handler_factory_ = NULL;
-    net_log_ = NULL;
-    network_delegate_ = NULL;
-  }
-  return session_;
+  return new HttpNetworkLayer(session);
 }
 
 // static
@@ -277,4 +226,59 @@
     }
   }
 }
+
+//-----------------------------------------------------------------------------
+
+int HttpNetworkLayer::CreateTransaction(scoped_ptr<HttpTransaction>* trans) {
+  if (suspended_)
+    return ERR_NETWORK_IO_SUSPENDED;
+
+  trans->reset(new HttpNetworkTransaction(GetSession()));
+  return OK;
+}
+
+HttpCache* HttpNetworkLayer::GetCache() {
+  return NULL;
+}
+
+HttpNetworkSession* HttpNetworkLayer::GetSession() {
+  if (!session_) {
+    DCHECK(proxy_service_);
+    if (!spdy_session_pool_.get())
+      spdy_session_pool_.reset(new SpdySessionPool(ssl_config_service_));
+    session_ = new HttpNetworkSession(
+        host_resolver_,
+        cert_verifier_,
+        dnsrr_resolver_,
+        dns_cert_checker_,
+        ssl_host_info_factory_,
+        proxy_service_,
+        socket_factory_,
+        ssl_config_service_,
+        spdy_session_pool_.release(),
+        http_auth_handler_factory_,
+        network_delegate_,
+        net_log_);
+    // These were just temps for lazy-initializing HttpNetworkSession.
+    host_resolver_ = NULL;
+    cert_verifier_ = NULL;
+    dnsrr_resolver_ = NULL;
+    dns_cert_checker_ = NULL;
+    ssl_host_info_factory_ = NULL;
+    proxy_service_ = NULL;
+    socket_factory_ = NULL;
+    http_auth_handler_factory_ = NULL;
+    net_log_ = NULL;
+    network_delegate_ = NULL;
+  }
+  return session_;
+}
+
+void HttpNetworkLayer::Suspend(bool suspend) {
+  suspended_ = suspend;
+
+  if (suspend && session_)
+    session_->tcp_socket_pool()->CloseIdleSockets();
+}
+
 }  // namespace net
diff --git a/net/http/http_network_layer.h b/net/http/http_network_layer.h
index 730b5c78..963ebee 100644
--- a/net/http/http_network_layer.h
+++ b/net/http/http_network_layer.h
@@ -78,6 +78,7 @@
       HttpAuthHandlerFactory* http_auth_handler_factory,
       HttpNetworkDelegate* network_delegate,
       NetLog* net_log);
+
   // Create a transaction factory that instantiate a network layer over an
   // existing network session. Network session contains some valuable
   // information (e.g. authentication data) that we want to share across
@@ -86,12 +87,6 @@
   // when network session is shared.
   static HttpTransactionFactory* CreateFactory(HttpNetworkSession* session);
 
-  // HttpTransactionFactory methods:
-  virtual int CreateTransaction(scoped_ptr<HttpTransaction>* trans);
-  virtual HttpCache* GetCache();
-  virtual HttpNetworkSession* GetSession();
-  virtual void Suspend(bool suspend);
-
   // Enable the spdy protocol.
   // Without calling this function, SPDY is disabled.  The mode can be:
   //   ""            : (default) SSL and compression are enabled, flow
@@ -102,6 +97,12 @@
   //   "none"        : disables both SSL and compression.
   static void EnableSpdy(const std::string& mode);
 
+  // HttpTransactionFactory methods:
+  virtual int CreateTransaction(scoped_ptr<HttpTransaction>* trans);
+  virtual HttpCache* GetCache();
+  virtual HttpNetworkSession* GetSession();
+  virtual void Suspend(bool suspend);
+
  private:
   // The factory we will use to create network sockets.
   ClientSocketFactory* socket_factory_;
diff --git a/net/http/http_request_headers.cc b/net/http/http_request_headers.cc
index 9ce77bf..9d523c1b 100644
--- a/net/http/http_request_headers.cc
+++ b/net/http/http_request_headers.cc
@@ -77,13 +77,6 @@
   headers_.clear();
 }
 
-void HttpRequestHeaders::SetHeaderIfMissing(const base::StringPiece& key,
-                                            const base::StringPiece& value) {
-  HeaderVector::iterator it = FindHeader(key);
-  if (it == headers_.end())
-    headers_.push_back(HeaderKeyValuePair(key.as_string(), value.as_string()));
-}
-
 void HttpRequestHeaders::SetHeader(const base::StringPiece& key,
                                    const base::StringPiece& value) {
   HeaderVector::iterator it = FindHeader(key);
@@ -93,6 +86,13 @@
     headers_.push_back(HeaderKeyValuePair(key.as_string(), value.as_string()));
 }
 
+void HttpRequestHeaders::SetHeaderIfMissing(const base::StringPiece& key,
+                                            const base::StringPiece& value) {
+  HeaderVector::iterator it = FindHeader(key);
+  if (it == headers_.end())
+    headers_.push_back(HeaderKeyValuePair(key.as_string(), value.as_string()));
+}
+
 void HttpRequestHeaders::RemoveHeader(const base::StringPiece& key) {
   HeaderVector::iterator it = FindHeader(key);
   if (it != headers_.end())
diff --git a/net/http/mock_gssapi_library_posix.cc b/net/http/mock_gssapi_library_posix.cc
index ec69964c..1ca50407 100644
--- a/net/http/mock_gssapi_library_posix.cc
+++ b/net/http/mock_gssapi_library_posix.cc
@@ -194,6 +194,23 @@
 MockGSSAPILibrary::~MockGSSAPILibrary() {
 }
 
+void MockGSSAPILibrary::ExpectSecurityContext(
+    const std::string& expected_package,
+    OM_uint32 response_code,
+    OM_uint32 minor_response_code,
+    const GssContextMockImpl& context_info,
+    const gss_buffer_desc& expected_input_token,
+    const gss_buffer_desc& output_token) {
+  SecurityContextQuery security_query;
+  security_query.expected_package = expected_package;
+  security_query.response_code = response_code;
+  security_query.minor_response_code = minor_response_code;
+  security_query.context_info.Assign(context_info);
+  security_query.expected_input_token = expected_input_token;
+  security_query.output_token = output_token;
+  expected_security_queries_.push_back(security_query);
+}
+
 bool MockGSSAPILibrary::Init() {
   return true;
 }
@@ -417,23 +434,6 @@
   return GSS_S_COMPLETE;
 }
 
-void MockGSSAPILibrary::ExpectSecurityContext(
-    const std::string& expected_package,
-    OM_uint32 response_code,
-    OM_uint32 minor_response_code,
-    const GssContextMockImpl& context_info,
-    const gss_buffer_desc& expected_input_token,
-    const gss_buffer_desc& output_token) {
-  SecurityContextQuery security_query;
-  security_query.expected_package = expected_package;
-  security_query.response_code = response_code;
-  security_query.minor_response_code = minor_response_code;
-  security_query.context_info.Assign(context_info);
-  security_query.expected_input_token = expected_input_token;
-  security_query.output_token = output_token;
-  expected_security_queries_.push_back(security_query);
-}
-
 }  // namespace test
 
 }  // namespace net
diff --git a/net/http/mock_gssapi_library_posix.h b/net/http/mock_gssapi_library_posix.h
index 15e14f2d..f0652d3 100644
--- a/net/http/mock_gssapi_library_posix.h
+++ b/net/http/mock_gssapi_library_posix.h
@@ -45,10 +45,61 @@
 // the system GSSAPI library calls.
 class MockGSSAPILibrary : public GSSAPILibrary {
  public:
+  // Unit tests need access to this. "Friend"ing didn't help.
+  struct SecurityContextQuery {
+    std::string expected_package;
+    OM_uint32 response_code;
+    OM_uint32 minor_response_code;
+    test::GssContextMockImpl context_info;
+    gss_buffer_desc expected_input_token;
+    gss_buffer_desc output_token;
+  };
 
   MockGSSAPILibrary();
   virtual ~MockGSSAPILibrary();
 
+  // Establishes an expectation for a |init_sec_context()| call.
+  //
+  // Each expectation established by |ExpectSecurityContext()| must be
+  // matched by a call to |init_sec_context()| during the lifetime of
+  // the MockGSSAPILibrary. The |expected_package| argument must equal the
+  // value associated with the |target_name| argument to |init_sec_context()|
+  // for there to be a match. The expectations also establish an explicit
+  // ordering.
+  //
+  // For example, this sequence will be successful.
+  //   MockGSSAPILibrary lib;
+  //   lib.ExpectSecurityContext("NTLM", ...)
+  //   lib.ExpectSecurityContext("Negotiate", ...)
+  //   lib.init_sec_context("NTLM", ...)
+  //   lib.init_sec_context("Negotiate", ...)
+  //
+  // This sequence will fail since the queries do not occur in the order
+  // established by the expectations.
+  //   MockGSSAPILibrary lib;
+  //   lib.ExpectSecurityContext("NTLM", ...)
+  //   lib.ExpectSecurityContext("Negotiate", ...)
+  //   lib.init_sec_context("Negotiate", ...)
+  //   lib.init_sec_context("NTLM", ...)
+  //
+  // This sequence will fail because there were not enough queries.
+  //   MockGSSAPILibrary lib;
+  //   lib.ExpectSecurityContext("NTLM", ...)
+  //   lib.ExpectSecurityContext("Negotiate", ...)
+  //   lib.init_sec_context("NTLM", ...)
+  //
+  // |response_code| is used as the return value for |init_sec_context()|.
+  // If |response_code| is GSS_S_COMPLETE,
+  //
+  // |context_info| is the expected value of the |**context_handle| in after
+  // |init_sec_context()| returns.
+  void ExpectSecurityContext(const std::string& expected_package,
+                             OM_uint32 response_code,
+                             OM_uint32 minor_response_code,
+                             const test::GssContextMockImpl& context_info,
+                             const gss_buffer_desc& expected_input_token,
+                             const gss_buffer_desc& output_token);
+
   // GSSAPILibrary methods:
 
   // Initializes the library, including any necessary dynamic libraries.
@@ -116,58 +167,6 @@
       int* locally_initiated,
       int* open);
 
-  // Establishes an expectation for a |init_sec_context()| call.
-  //
-  // Each expectation established by |ExpectSecurityContext()| must be
-  // matched by a call to |init_sec_context()| during the lifetime of
-  // the MockGSSAPILibrary. The |expected_package| argument must equal the
-  // value associated with the |target_name| argument to |init_sec_context()|
-  // for there to be a match. The expectations also establish an explicit
-  // ordering.
-  //
-  // For example, this sequence will be successful.
-  //   MockGSSAPILibrary lib;
-  //   lib.ExpectSecurityContext("NTLM", ...)
-  //   lib.ExpectSecurityContext("Negotiate", ...)
-  //   lib.init_sec_context("NTLM", ...)
-  //   lib.init_sec_context("Negotiate", ...)
-  //
-  // This sequence will fail since the queries do not occur in the order
-  // established by the expectations.
-  //   MockGSSAPILibrary lib;
-  //   lib.ExpectSecurityContext("NTLM", ...)
-  //   lib.ExpectSecurityContext("Negotiate", ...)
-  //   lib.init_sec_context("Negotiate", ...)
-  //   lib.init_sec_context("NTLM", ...)
-  //
-  // This sequence will fail because there were not enough queries.
-  //   MockGSSAPILibrary lib;
-  //   lib.ExpectSecurityContext("NTLM", ...)
-  //   lib.ExpectSecurityContext("Negotiate", ...)
-  //   lib.init_sec_context("NTLM", ...)
-  //
-  // |response_code| is used as the return value for |init_sec_context()|.
-  // If |response_code| is GSS_S_COMPLETE,
-  //
-  // |context_info| is the expected value of the |**context_handle| in after
-  // |init_sec_context()| returns.
-  void ExpectSecurityContext(const std::string& expected_package,
-                             OM_uint32 response_code,
-                             OM_uint32 minor_response_code,
-                             const test::GssContextMockImpl& context_info,
-                             const gss_buffer_desc& expected_input_token,
-                             const gss_buffer_desc& output_token);
-
-  // Unit tests need access to this. "Friend"ing didn't help.
-  struct SecurityContextQuery {
-    std::string expected_package;
-    OM_uint32 response_code;
-    OM_uint32 minor_response_code;
-    test::GssContextMockImpl context_info;
-    gss_buffer_desc expected_input_token;
-    gss_buffer_desc output_token;
-  };
-
  private:
   FRIEND_TEST_ALL_PREFIXES(HttpAuthGSSAPIPOSIXTest, GSSAPICycle);
 
diff --git a/net/proxy/proxy_list.cc b/net/proxy/proxy_list.cc
index 236e7078..011aab9 100644
--- a/net/proxy/proxy_list.cc
+++ b/net/proxy/proxy_list.cc
@@ -86,17 +86,6 @@
   return proxies_[0];
 }
 
-std::string ProxyList::ToPacString() const {
-  std::string proxy_list;
-  std::vector<ProxyServer>::const_iterator iter = proxies_.begin();
-  for (; iter != proxies_.end(); ++iter) {
-    if (!proxy_list.empty())
-      proxy_list += ";";
-    proxy_list += iter->ToPacString();
-  }
-  return proxy_list.empty() ? std::string() : proxy_list;
-}
-
 void ProxyList::SetFromPacString(const std::string& pac_string) {
   StringTokenizer entry_tok(pac_string, ";");
   proxies_.clear();
@@ -115,6 +104,17 @@
   }
 }
 
+std::string ProxyList::ToPacString() const {
+  std::string proxy_list;
+  std::vector<ProxyServer>::const_iterator iter = proxies_.begin();
+  for (; iter != proxies_.end(); ++iter) {
+    if (!proxy_list.empty())
+      proxy_list += ";";
+    proxy_list += iter->ToPacString();
+  }
+  return proxy_list.empty() ? std::string() : proxy_list;
+}
+
 bool ProxyList::Fallback(ProxyRetryInfoMap* proxy_retry_info) {
   // Number of minutes to wait before retrying a bad proxy server.
   const TimeDelta kProxyRetryDelay = TimeDelta::FromMinutes(5);
diff --git a/net/socket/client_socket.cc b/net/socket/client_socket.cc
index 6b12841ee..3792c5c 100644
--- a/net/socket/client_socket.cc
+++ b/net/socket/client_socket.cc
@@ -66,42 +66,6 @@
   // are intentionally preserved.
 }
 
-void ClientSocket::UseHistory::EmitPreconnectionHistograms() const {
-  DCHECK(!subresource_speculation_ || !omnibox_speculation_);
-  // 0 ==> non-speculative, never connected.
-  // 1 ==> non-speculative never used (but connected).
-  // 2 ==> non-speculative and used.
-  // 3 ==> omnibox_speculative never connected.
-  // 4 ==> omnibox_speculative never used (but connected).
-  // 5 ==> omnibox_speculative and used.
-  // 6 ==> subresource_speculative never connected.
-  // 7 ==> subresource_speculative never used (but connected).
-  // 8 ==> subresource_speculative and used.
-  int result;
-  if (was_used_to_convey_data_)
-    result = 2;
-  else if (was_ever_connected_)
-    result = 1;
-  else
-    result = 0;  // Never used, and not really connected.
-
-  if (omnibox_speculation_)
-    result += 3;
-  else if (subresource_speculation_)
-    result += 6;
-  UMA_HISTOGRAM_ENUMERATION("Net.PreconnectUtilization2", result, 9);
-
-  static const bool connect_backup_jobs_fieldtrial =
-      base::FieldTrialList::Find("ConnnectBackupJobs") &&
-      !base::FieldTrialList::Find("ConnnectBackupJobs")->group_name().empty();
-  if (connect_backup_jobs_fieldtrial) {
-    UMA_HISTOGRAM_ENUMERATION(
-        base::FieldTrial::MakeName("Net.PreconnectUtilization2",
-                                   "ConnnectBackupJobs"),
-        result, 9);
-  }
-}
-
 void ClientSocket::UseHistory::set_was_ever_connected() {
   DCHECK(!was_used_to_convey_data_);
   was_ever_connected_ = true;
@@ -144,6 +108,42 @@
   return was_used_to_convey_data_;
 }
 
+void ClientSocket::UseHistory::EmitPreconnectionHistograms() const {
+  DCHECK(!subresource_speculation_ || !omnibox_speculation_);
+  // 0 ==> non-speculative, never connected.
+  // 1 ==> non-speculative never used (but connected).
+  // 2 ==> non-speculative and used.
+  // 3 ==> omnibox_speculative never connected.
+  // 4 ==> omnibox_speculative never used (but connected).
+  // 5 ==> omnibox_speculative and used.
+  // 6 ==> subresource_speculative never connected.
+  // 7 ==> subresource_speculative never used (but connected).
+  // 8 ==> subresource_speculative and used.
+  int result;
+  if (was_used_to_convey_data_)
+    result = 2;
+  else if (was_ever_connected_)
+    result = 1;
+  else
+    result = 0;  // Never used, and not really connected.
+
+  if (omnibox_speculation_)
+    result += 3;
+  else if (subresource_speculation_)
+    result += 6;
+  UMA_HISTOGRAM_ENUMERATION("Net.PreconnectUtilization2", result, 9);
+
+  static const bool connect_backup_jobs_fieldtrial =
+      base::FieldTrialList::Find("ConnnectBackupJobs") &&
+      !base::FieldTrialList::Find("ConnnectBackupJobs")->group_name().empty();
+  if (connect_backup_jobs_fieldtrial) {
+    UMA_HISTOGRAM_ENUMERATION(
+        base::FieldTrial::MakeName("Net.PreconnectUtilization2",
+                                   "ConnnectBackupJobs"),
+        result, 9);
+  }
+}
+
 void ClientSocket::LogByteTransfer(const BoundNetLog& net_log,
                                    NetLog::EventType event_type,
                                    int byte_count,
diff --git a/net/socket/client_socket_factory.cc b/net/socket/client_socket_factory.cc
index f4da066f..dd201f97 100644
--- a/net/socket/client_socket_factory.cc
+++ b/net/socket/client_socket_factory.cc
@@ -79,17 +79,6 @@
 
 }  // namespace
 
-// static
-ClientSocketFactory* ClientSocketFactory::GetDefaultFactory() {
-  return g_default_client_socket_factory.Pointer();
-}
-
-// static
-void ClientSocketFactory::SetSSLClientSocketFactory(
-    SSLClientSocketFactory factory) {
-  g_ssl_factory = factory;
-}
-
 // Deprecated function (http://crbug.com/37810) that takes a ClientSocket.
 SSLClientSocket* ClientSocketFactory::CreateSSLClientSocket(
     ClientSocket* transport_socket,
@@ -104,4 +93,15 @@
                                NULL /* DnsCertProvenanceChecker */);
 }
 
+// static
+ClientSocketFactory* ClientSocketFactory::GetDefaultFactory() {
+  return g_default_client_socket_factory.Pointer();
+}
+
+// static
+void ClientSocketFactory::SetSSLClientSocketFactory(
+    SSLClientSocketFactory factory) {
+  g_ssl_factory = factory;
+}
+
 }  // namespace net
diff --git a/net/socket/dns_cert_provenance_checker.cc b/net/socket/dns_cert_provenance_checker.cc
index 665a16a..33487c5 100644
--- a/net/socket/dns_cert_provenance_checker.cc
+++ b/net/socket/dns_cert_provenance_checker.cc
@@ -218,6 +218,22 @@
 
 }  // namespace
 
+DnsCertProvenanceChecker::Delegate::~Delegate() {
+}
+
+DnsCertProvenanceChecker::~DnsCertProvenanceChecker() {
+}
+
+void DnsCertProvenanceChecker::DoAsyncLookup(
+    const std::string& hostname,
+    const std::vector<base::StringPiece>& der_certs,
+    DnsRRResolver* dnsrr_resolver,
+    Delegate* delegate) {
+  DnsCertProvenanceCheck* check = new DnsCertProvenanceCheck(
+      hostname, dnsrr_resolver, delegate, der_certs);
+  check->Start();
+}
+
 // static
 std::string DnsCertProvenanceChecker::BuildEncryptedReport(
     const std::string& hostname,
@@ -318,32 +334,16 @@
                      outer.size());
 }
 
-void DnsCertProvenanceChecker::DoAsyncLookup(
-    const std::string& hostname,
-    const std::vector<base::StringPiece>& der_certs,
-    DnsRRResolver* dnsrr_resolver,
-    Delegate* delegate) {
-  DnsCertProvenanceCheck* check = new DnsCertProvenanceCheck(
-      hostname, dnsrr_resolver, delegate, der_certs);
-  check->Start();
-}
-
-DnsCertProvenanceChecker::Delegate::~Delegate() {
-}
-
-DnsCertProvenanceChecker::~DnsCertProvenanceChecker() {
-}
-
 }  // namespace net
 
 #else  // USE_OPENSSL
 
 namespace net {
 
-std::string DnsCertProvenanceChecker::BuildEncryptedReport(
-    const std::string& hostname,
-    const std::vector<std::string>& der_certs) {
-  return "";
+DnsCertProvenanceChecker::Delegate::~Delegate() {
+}
+
+DnsCertProvenanceChecker::~DnsCertProvenanceChecker() {
 }
 
 void DnsCertProvenanceChecker::DoAsyncLookup(
@@ -353,10 +353,10 @@
     Delegate* delegate) {
 }
 
-DnsCertProvenanceChecker::Delegate::~Delegate() {
-}
-
-DnsCertProvenanceChecker::~DnsCertProvenanceChecker() {
+std::string DnsCertProvenanceChecker::BuildEncryptedReport(
+    const std::string& hostname,
+    const std::vector<std::string>& der_certs) {
+  return "";
 }
 
 }  // namespace net
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc
index d006d58..a71af2c 100644
--- a/net/socket/ssl_client_socket_nss.cc
+++ b/net/socket/ssl_client_socket_nss.cc
@@ -279,6 +279,162 @@
   CERTCertificate** certs_;
 };
 
+void DestroyCertificates(CERTCertificate** certs, unsigned len) {
+  for (unsigned i = 0; i < len; i++)
+    CERT_DestroyCertificate(certs[i]);
+}
+
+// DNSValidationResult enumerates the possible outcomes from processing a
+// set of DNS records.
+enum DNSValidationResult {
+  DNSVR_SUCCESS,   // the cert is immediately acceptable.
+  DNSVR_FAILURE,   // the cert is unconditionally rejected.
+  DNSVR_CONTINUE,  // perform CA validation as usual.
+};
+
+// VerifyTXTRecords processes the RRDATA for a number of DNS TXT records and
+// checks them against the given certificate.
+//   dnssec: if true then the TXT records are DNSSEC validated. In this case,
+//       DNSVR_SUCCESS may be returned.
+//    server_cert_nss: the certificate to validate
+//    rrdatas: the TXT records for the current domain.
+DNSValidationResult VerifyTXTRecords(
+    bool dnssec,
+    CERTCertificate* server_cert_nss,
+    const std::vector<base::StringPiece>& rrdatas) {
+  bool found_well_formed_record = false;
+  bool matched_record = false;
+
+  for (std::vector<base::StringPiece>::const_iterator
+       i = rrdatas.begin(); i != rrdatas.end(); ++i) {
+    std::map<std::string, std::string> m(
+        DNSSECChainVerifier::ParseTLSTXTRecord(*i));
+    if (m.empty())
+      continue;
+
+    std::map<std::string, std::string>::const_iterator j;
+    j = m.find("v");
+    if (j == m.end() || j->second != "tls1")
+      continue;
+
+    j = m.find("ha");
+
+    HASH_HashType hash_algorithm;
+    unsigned hash_length;
+    if (j == m.end() || j->second == "sha1") {
+      hash_algorithm = HASH_AlgSHA1;
+      hash_length = SHA1_LENGTH;
+    } else if (j->second == "sha256") {
+      hash_algorithm = HASH_AlgSHA256;
+      hash_length = SHA256_LENGTH;
+    } else {
+      continue;
+    }
+
+    j = m.find("h");
+    if (j == m.end())
+      continue;
+
+    std::vector<uint8> given_hash;
+    if (!base::HexStringToBytes(j->second, &given_hash))
+      continue;
+
+    if (given_hash.size() != hash_length)
+      continue;
+
+    uint8 calculated_hash[SHA256_LENGTH];  // SHA256 is the largest.
+    SECStatus rv;
+
+    j = m.find("hr");
+    if (j == m.end() || j->second == "pubkey") {
+      rv = HASH_HashBuf(hash_algorithm, calculated_hash,
+                        server_cert_nss->derPublicKey.data,
+                        server_cert_nss->derPublicKey.len);
+    } else if (j->second == "cert") {
+      rv = HASH_HashBuf(hash_algorithm, calculated_hash,
+                        server_cert_nss->derCert.data,
+                        server_cert_nss->derCert.len);
+    } else {
+      continue;
+    }
+
+    if (rv != SECSuccess)
+      NOTREACHED();
+
+    found_well_formed_record = true;
+
+    if (memcmp(calculated_hash, &given_hash[0], hash_length) == 0) {
+      matched_record = true;
+      if (dnssec)
+        return DNSVR_SUCCESS;
+    }
+  }
+
+  if (found_well_formed_record && !matched_record)
+    return DNSVR_FAILURE;
+
+  return DNSVR_CONTINUE;
+}
+
+// CheckDNSSECChain tries to validate a DNSSEC chain embedded in
+// |server_cert_nss_|. It returns true iff a chain is found that proves the
+// value of a TXT record that contains a valid public key fingerprint.
+DNSValidationResult CheckDNSSECChain(
+    const std::string& hostname,
+    CERTCertificate* server_cert_nss) {
+  if (!server_cert_nss)
+    return DNSVR_CONTINUE;
+
+  // CERT_FindCertExtensionByOID isn't exported so we have to install an OID,
+  // get a tag for it and find the extension by using that tag.
+  static SECOidTag dnssec_chain_tag;
+  static bool dnssec_chain_tag_valid;
+  if (!dnssec_chain_tag_valid) {
+    // It's harmless if multiple threads enter this block concurrently.
+    static const uint8 kDNSSECChainOID[] =
+        // 1.3.6.1.4.1.11129.2.1.4
+        // (iso.org.dod.internet.private.enterprises.google.googleSecurity.
+        //  certificateExtensions.dnssecEmbeddedChain)
+        {0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x01, 0x04};
+    SECOidData oid_data;
+    memset(&oid_data, 0, sizeof(oid_data));
+    oid_data.oid.data = const_cast<uint8*>(kDNSSECChainOID);
+    oid_data.oid.len = sizeof(kDNSSECChainOID);
+    oid_data.desc = "DNSSEC chain";
+    oid_data.supportedExtension = SUPPORTED_CERT_EXTENSION;
+    dnssec_chain_tag = SECOID_AddEntry(&oid_data);
+    DCHECK_NE(SEC_OID_UNKNOWN, dnssec_chain_tag);
+    dnssec_chain_tag_valid = true;
+  }
+
+  SECItem dnssec_embedded_chain;
+  SECStatus rv = CERT_FindCertExtension(server_cert_nss,
+      dnssec_chain_tag, &dnssec_embedded_chain);
+  if (rv != SECSuccess)
+    return DNSVR_CONTINUE;
+
+  base::StringPiece chain(
+      reinterpret_cast<char*>(dnssec_embedded_chain.data),
+      dnssec_embedded_chain.len);
+  std::string dns_hostname;
+  if (!DNSDomainFromDot(hostname, &dns_hostname))
+    return DNSVR_CONTINUE;
+  DNSSECChainVerifier verifier(dns_hostname, chain);
+  DNSSECChainVerifier::Error err = verifier.Verify();
+  if (err != DNSSECChainVerifier::OK) {
+    LOG(ERROR) << "DNSSEC chain verification failed: " << err;
+    return DNSVR_CONTINUE;
+  }
+
+  if (verifier.rrtype() != kDNS_TXT)
+    return DNSVR_CONTINUE;
+
+  DNSValidationResult r = VerifyTXTRecords(
+      true /* DNSSEC verified */, server_cert_nss, verifier.rrdatas());
+  SECITEM_FreeItem(&dnssec_embedded_chain, PR_FALSE);
+  return r;
+}
+
 }  // namespace
 
 SSLClientSocketNSS::SSLClientSocketNSS(ClientSocketHandle* transport_socket,
@@ -333,156 +489,94 @@
   LeaveFunction("");
 }
 
-int SSLClientSocketNSS::Init() {
+// static
+void SSLClientSocketNSS::ClearSessionCache() {
+  SSL_ClearSessionCache();
+}
+
+void SSLClientSocketNSS::GetSSLInfo(SSLInfo* ssl_info) {
   EnterFunction("");
-  // Initialize the NSS SSL library in a threadsafe way.  This also
-  // initializes the NSS base library.
-  EnsureNSSSSLInit();
-  if (!NSS_IsInitialized())
-    return ERR_UNEXPECTED;
-#if !defined(OS_MACOSX) && !defined(OS_WIN)
-  // We must call EnsureOCSPInit() here, on the IO thread, to get the IO loop
-  // by MessageLoopForIO::current().
-  // X509Certificate::Verify() runs on a worker thread of CertVerifier.
-  EnsureOCSPInit();
-#endif
+  ssl_info->Reset();
 
-  LeaveFunction("");
-  return OK;
-}
-
-// SaveSnapStartInfo extracts the information needed to perform a Snap Start
-// with this server in the future (if any) and tells |ssl_host_info_| to
-// preserve it.
-void SSLClientSocketNSS::SaveSnapStartInfo() {
-  if (!ssl_host_info_.get())
-    return;
-
-  // If the SSLHostInfo hasn't managed to load from disk yet then we can't save
-  // anything.
-  if (ssl_host_info_->WaitForDataReady(NULL) != OK)
-    return;
-
-  SECStatus rv;
-  SSLSnapStartResult snap_start_type;
-  rv = SSL_GetSnapStartResult(nss_fd_, &snap_start_type);
-  if (rv != SECSuccess) {
-    NOTREACHED();
-    return;
-  }
-  net_log_.AddEvent(NetLog::TYPE_SSL_SNAP_START,
-                    new NetLogIntegerParameter("type", snap_start_type));
-  if (snap_start_type == SSL_SNAP_START_FULL ||
-      snap_start_type == SSL_SNAP_START_RESUME) {
-    // If we did a successful Snap Start then our information was correct and
-    // there's no point saving it again.
+  if (!server_cert_) {
+    LOG(DFATAL) << "!server_cert_";
     return;
   }
 
-  const unsigned char* hello_data;
-  unsigned hello_data_len;
-  rv = SSL_GetPredictedServerHelloData(nss_fd_, &hello_data, &hello_data_len);
-  if (rv != SECSuccess) {
-    NOTREACHED();
-    return;
-  }
-  if (hello_data_len > std::numeric_limits<uint16>::max())
-    return;
-  SSLHostInfo::State* state = ssl_host_info_->mutable_state();
+  ssl_info->cert_status = server_cert_verify_result_->cert_status;
+  DCHECK(server_cert_ != NULL);
+  ssl_info->cert = server_cert_;
+  ssl_info->connection_status = ssl_connection_status_;
 
-  if (hello_data_len > 0) {
-    state->server_hello =
-        std::string(reinterpret_cast<const char *>(hello_data), hello_data_len);
-    state->npn_valid = true;
-    state->npn_status = GetNextProto(&state->npn_protocol);
+  PRUint16 cipher_suite =
+      SSLConnectionStatusToCipherSuite(ssl_connection_status_);
+  SSLCipherSuiteInfo cipher_info;
+  SECStatus ok = SSL_GetCipherSuiteInfo(cipher_suite,
+                                        &cipher_info, sizeof(cipher_info));
+  if (ok == SECSuccess) {
+    ssl_info->security_bits = cipher_info.effectiveKeyBits;
   } else {
-    state->server_hello.clear();
-    state->npn_valid = false;
+    ssl_info->security_bits = -1;
+    LOG(DFATAL) << "SSL_GetCipherSuiteInfo returned " << PR_GetError()
+                << " for cipherSuite " << cipher_suite;
   }
-
-  state->certs.clear();
-  PeerCertificateChain certs(nss_fd_);
-  for (unsigned i = 0; i < certs.size(); i++) {
-    if (certs[i]->derCert.len > std::numeric_limits<uint16>::max())
-      return;
-
-    state->certs.push_back(std::string(
-          reinterpret_cast<char*>(certs[i]->derCert.data),
-          certs[i]->derCert.len));
-  }
-
-  ssl_host_info_->Persist();
+  LeaveFunction("");
 }
 
-static void DestroyCertificates(CERTCertificate** certs, unsigned len) {
-  for (unsigned i = 0; i < len; i++)
-    CERT_DestroyCertificate(certs[i]);
+void SSLClientSocketNSS::GetSSLCertRequestInfo(
+    SSLCertRequestInfo* cert_request_info) {
+  EnterFunction("");
+  // TODO(rch): switch SSLCertRequestInfo.host_and_port to a HostPortPair
+  cert_request_info->host_and_port = host_and_port_.ToString();
+  cert_request_info->client_certs = client_certs_;
+  LeaveFunction(cert_request_info->client_certs.size());
 }
 
-// LoadSnapStartInfo parses |info|, which contains data previously serialised
-// by |SaveSnapStartInfo|, and sets the predicted certificates and ServerHello
-// data on the NSS socket. Returns true on success. If this function returns
-// false, the caller should try a normal TLS handshake.
-bool SSLClientSocketNSS::LoadSnapStartInfo() {
-  const SSLHostInfo::State& state(ssl_host_info_->state());
-
-  if (state.server_hello.empty() ||
-      state.certs.empty() ||
-      !state.npn_valid) {
-    return false;
+SSLClientSocket::NextProtoStatus
+SSLClientSocketNSS::GetNextProto(std::string* proto) {
+#if defined(SSL_NEXT_PROTO_NEGOTIATED)
+  if (!handshake_callback_called_) {
+    DCHECK(pseudo_connected_);
+    predicted_npn_proto_used_ = true;
+    *proto = predicted_npn_proto_;
+    return predicted_npn_status_;
   }
 
-  SECStatus rv;
-  rv = SSL_SetPredictedServerHelloData(
-      nss_fd_,
-      reinterpret_cast<const uint8*>(state.server_hello.data()),
-      state.server_hello.size());
-  DCHECK_EQ(SECSuccess, rv);
-
-  const std::vector<std::string>& certs_in = state.certs;
-  scoped_array<CERTCertificate*> certs(new CERTCertificate*[certs_in.size()]);
-  for (size_t i = 0; i < certs_in.size(); i++) {
-    SECItem derCert;
-    derCert.data =
-        const_cast<uint8*>(reinterpret_cast<const uint8*>(certs_in[i].data()));
-    derCert.len = certs_in[i].size();
-    certs[i] = CERT_NewTempCertificate(
-        CERT_GetDefaultCertDB(), &derCert, NULL /* no nickname given */,
-        PR_FALSE /* not permanent */, PR_TRUE /* copy DER data */);
-    if (!certs[i]) {
-      DestroyCertificates(&certs[0], i);
-      NOTREACHED();
-      return false;
-    }
+  unsigned char buf[255];
+  int state;
+  unsigned len;
+  SECStatus rv = SSL_GetNextProto(nss_fd_, &state, buf, &len, sizeof(buf));
+  if (rv != SECSuccess) {
+    NOTREACHED() << "Error return from SSL_GetNextProto: " << rv;
+    proto->clear();
+    return kNextProtoUnsupported;
   }
-
-  rv = SSL_SetPredictedPeerCertificates(nss_fd_, certs.get(), certs_in.size());
-  DestroyCertificates(&certs[0], certs_in.size());
-  DCHECK_EQ(SECSuccess, rv);
-
-  if (state.npn_valid) {
-    predicted_npn_status_ = state.npn_status;
-    predicted_npn_proto_ = state.npn_protocol;
+  // We don't check for truncation because sizeof(buf) is large enough to hold
+  // the maximum protocol size.
+  switch (state) {
+    case SSL_NEXT_PROTO_NO_SUPPORT:
+      proto->clear();
+      return kNextProtoUnsupported;
+    case SSL_NEXT_PROTO_NEGOTIATED:
+      *proto = std::string(reinterpret_cast<char*>(buf), len);
+      return kNextProtoNegotiated;
+    case SSL_NEXT_PROTO_NO_OVERLAP:
+      *proto = std::string(reinterpret_cast<char*>(buf), len);
+      return kNextProtoNoOverlap;
+    default:
+      NOTREACHED() << "Unknown status from SSL_GetNextProto: " << state;
+      proto->clear();
+      return kNextProtoUnsupported;
   }
-
-  return true;
+#else
+  // No NPN support in the libssl that we are building with.
+  proto->clear();
+  return kNextProtoUnsupported;
+#endif
 }
 
-bool SSLClientSocketNSS::IsNPNProtocolMispredicted() {
-  DCHECK(handshake_callback_called_);
-  if (!predicted_npn_proto_used_)
-    return false;
-  std::string npn_proto;
-  GetNextProto(&npn_proto);
-  return predicted_npn_proto_ != npn_proto;
-}
-
-void SSLClientSocketNSS::UncorkAfterTimeout() {
-  corked_ = false;
-  int nsent;
-  do {
-    nsent = BufferSend();
-  } while (nsent > 0);
+void SSLClientSocketNSS::UseDNSSEC(DNSSECProvider* provider) {
+  dnssec_provider_ = provider;
 }
 
 int SSLClientSocketNSS::Connect(CompletionCallback* callback) {
@@ -542,6 +636,228 @@
   return rv > OK ? OK : rv;
 }
 
+void SSLClientSocketNSS::Disconnect() {
+  EnterFunction("");
+
+  // TODO(wtc): Send SSL close_notify alert.
+  if (nss_fd_ != NULL) {
+    PR_Close(nss_fd_);
+    nss_fd_ = NULL;
+  }
+
+  // Shut down anything that may call us back (through buffer_send_callback_,
+  // buffer_recv_callback, or handshake_io_callback_).
+  verifier_.reset();
+  transport_->socket()->Disconnect();
+
+  // Reset object state
+  transport_send_busy_   = false;
+  transport_recv_busy_   = false;
+  user_connect_callback_ = NULL;
+  user_read_callback_    = NULL;
+  user_write_callback_   = NULL;
+  user_read_buf_         = NULL;
+  user_read_buf_len_     = 0;
+  user_write_buf_        = NULL;
+  user_write_buf_len_    = 0;
+  server_cert_           = NULL;
+  if (server_cert_nss_) {
+    CERT_DestroyCertificate(server_cert_nss_);
+    server_cert_nss_     = NULL;
+  }
+  local_server_cert_verify_result_.Reset();
+  server_cert_verify_result_ = NULL;
+  ssl_connection_status_ = 0;
+  completed_handshake_   = false;
+  pseudo_connected_      = false;
+  eset_mitm_detected_    = false;
+  start_cert_verification_time_ = base::TimeTicks();
+  predicted_cert_chain_correct_ = false;
+  peername_initialized_  = false;
+  nss_bufs_              = NULL;
+  client_certs_.clear();
+  client_auth_cert_needed_ = false;
+
+  LeaveFunction("");
+}
+
+bool SSLClientSocketNSS::IsConnected() const {
+  // Ideally, we should also check if we have received the close_notify alert
+  // message from the server, and return false in that case.  We're not doing
+  // that, so this function may return a false positive.  Since the upper
+  // layer (HttpNetworkTransaction) needs to handle a persistent connection
+  // closed by the server when we send a request anyway, a false positive in
+  // exchange for simpler code is a good trade-off.
+  EnterFunction("");
+  bool ret = (pseudo_connected_ || completed_handshake_) &&
+             transport_->socket()->IsConnected();
+  LeaveFunction("");
+  return ret;
+}
+
+bool SSLClientSocketNSS::IsConnectedAndIdle() const {
+  // Unlike IsConnected, this method doesn't return a false positive.
+  //
+  // Strictly speaking, we should check if we have received the close_notify
+  // alert message from the server, and return false in that case.  Although
+  // the close_notify alert message means EOF in the SSL layer, it is just
+  // bytes to the transport layer below, so
+  // transport_->socket()->IsConnectedAndIdle() returns the desired false
+  // when we receive close_notify.
+  EnterFunction("");
+  bool ret = (pseudo_connected_ || completed_handshake_) &&
+             transport_->socket()->IsConnectedAndIdle();
+  LeaveFunction("");
+  return ret;
+}
+
+int SSLClientSocketNSS::GetPeerAddress(AddressList* address) const {
+  return transport_->socket()->GetPeerAddress(address);
+}
+
+const BoundNetLog& SSLClientSocketNSS::NetLog() const {
+  return net_log_;
+}
+
+void SSLClientSocketNSS::SetSubresourceSpeculation() {
+  if (transport_.get() && transport_->socket()) {
+    transport_->socket()->SetSubresourceSpeculation();
+  } else {
+    NOTREACHED();
+  }
+}
+
+void SSLClientSocketNSS::SetOmniboxSpeculation() {
+  if (transport_.get() && transport_->socket()) {
+    transport_->socket()->SetOmniboxSpeculation();
+  } else {
+    NOTREACHED();
+  }
+}
+
+bool SSLClientSocketNSS::WasEverUsed() const {
+  if (transport_.get() && transport_->socket()) {
+    return transport_->socket()->WasEverUsed();
+  }
+  NOTREACHED();
+  return false;
+}
+
+bool SSLClientSocketNSS::UsingTCPFastOpen() const {
+  if (transport_.get() && transport_->socket()) {
+    return transport_->socket()->UsingTCPFastOpen();
+  }
+  NOTREACHED();
+  return false;
+}
+
+int SSLClientSocketNSS::Read(IOBuffer* buf, int buf_len,
+                             CompletionCallback* callback) {
+  EnterFunction(buf_len);
+  DCHECK(!user_read_callback_);
+  DCHECK(!user_connect_callback_);
+  DCHECK(!user_read_buf_);
+  DCHECK(nss_bufs_);
+
+  user_read_buf_ = buf;
+  user_read_buf_len_ = buf_len;
+
+  if (!completed_handshake_) {
+    // In this case we have lied about being connected in order to merge the
+    // first Write into a Snap Start handshake. We'll leave the read hanging
+    // until the handshake has completed.
+    DCHECK(pseudo_connected_);
+
+    user_read_callback_ = callback;
+    LeaveFunction(ERR_IO_PENDING);
+    return ERR_IO_PENDING;
+  }
+
+  int rv = DoReadLoop(OK);
+
+  if (rv == ERR_IO_PENDING) {
+    user_read_callback_ = callback;
+  } else {
+    user_read_buf_ = NULL;
+    user_read_buf_len_ = 0;
+  }
+  LeaveFunction(rv);
+  return rv;
+}
+
+int SSLClientSocketNSS::Write(IOBuffer* buf, int buf_len,
+                              CompletionCallback* callback) {
+  EnterFunction(buf_len);
+  if (!pseudo_connected_) {
+    DCHECK(completed_handshake_);
+    DCHECK(next_handshake_state_ == STATE_NONE);
+    DCHECK(!user_connect_callback_);
+  }
+  DCHECK(!user_write_callback_);
+  DCHECK(!user_write_buf_);
+  DCHECK(nss_bufs_);
+
+  user_write_buf_ = buf;
+  user_write_buf_len_ = buf_len;
+
+  if (next_handshake_state_ == STATE_SNAP_START_WAIT_FOR_WRITE) {
+    // We lied about being connected and we have been waiting for this write in
+    // order to merge it into the Snap Start handshake. We'll leave the write
+    // pending until the handshake completes.
+    DCHECK(pseudo_connected_);
+    int rv = DoHandshakeLoop(OK);
+    if (rv == ERR_IO_PENDING) {
+      user_write_callback_ = callback;
+    } else {
+      user_write_buf_ = NULL;
+      user_write_buf_len_ = 0;
+    }
+    if (rv != OK)
+      return rv;
+  }
+
+  if (corked_) {
+    corked_ = false;
+    uncork_timer_.Reset();
+  }
+  int rv = DoWriteLoop(OK);
+
+  if (rv == ERR_IO_PENDING) {
+    user_write_callback_ = callback;
+  } else {
+    user_write_buf_ = NULL;
+    user_write_buf_len_ = 0;
+  }
+  LeaveFunction(rv);
+  return rv;
+}
+
+bool SSLClientSocketNSS::SetReceiveBufferSize(int32 size) {
+  return transport_->socket()->SetReceiveBufferSize(size);
+}
+
+bool SSLClientSocketNSS::SetSendBufferSize(int32 size) {
+  return transport_->socket()->SetSendBufferSize(size);
+}
+
+int SSLClientSocketNSS::Init() {
+  EnterFunction("");
+  // Initialize the NSS SSL library in a threadsafe way.  This also
+  // initializes the NSS base library.
+  EnsureNSSSSLInit();
+  if (!NSS_IsInitialized())
+    return ERR_UNEXPECTED;
+#if !defined(OS_MACOSX) && !defined(OS_WIN)
+  // We must call EnsureOCSPInit() here, on the IO thread, to get the IO loop
+  // by MessageLoopForIO::current().
+  // X509Certificate::Verify() runs on a worker thread of CertVerifier.
+  EnsureOCSPInit();
+#endif
+
+  LeaveFunction("");
+  return OK;
+}
+
 int SSLClientSocketNSS::InitializeSSLOptions() {
   // Transport connected, now hook it up to nss
   // TODO(port): specify rx and tx buffer sizes separately
@@ -764,214 +1080,6 @@
   return OK;
 }
 
-void SSLClientSocketNSS::Disconnect() {
-  EnterFunction("");
-
-  // TODO(wtc): Send SSL close_notify alert.
-  if (nss_fd_ != NULL) {
-    PR_Close(nss_fd_);
-    nss_fd_ = NULL;
-  }
-
-  // Shut down anything that may call us back (through buffer_send_callback_,
-  // buffer_recv_callback, or handshake_io_callback_).
-  verifier_.reset();
-  transport_->socket()->Disconnect();
-
-  // Reset object state
-  transport_send_busy_   = false;
-  transport_recv_busy_   = false;
-  user_connect_callback_ = NULL;
-  user_read_callback_    = NULL;
-  user_write_callback_   = NULL;
-  user_read_buf_         = NULL;
-  user_read_buf_len_     = 0;
-  user_write_buf_        = NULL;
-  user_write_buf_len_    = 0;
-  server_cert_           = NULL;
-  if (server_cert_nss_) {
-    CERT_DestroyCertificate(server_cert_nss_);
-    server_cert_nss_     = NULL;
-  }
-  local_server_cert_verify_result_.Reset();
-  server_cert_verify_result_ = NULL;
-  ssl_connection_status_ = 0;
-  completed_handshake_   = false;
-  pseudo_connected_      = false;
-  eset_mitm_detected_    = false;
-  start_cert_verification_time_ = base::TimeTicks();
-  predicted_cert_chain_correct_ = false;
-  peername_initialized_  = false;
-  nss_bufs_              = NULL;
-  client_certs_.clear();
-  client_auth_cert_needed_ = false;
-
-  LeaveFunction("");
-}
-
-bool SSLClientSocketNSS::IsConnected() const {
-  // Ideally, we should also check if we have received the close_notify alert
-  // message from the server, and return false in that case.  We're not doing
-  // that, so this function may return a false positive.  Since the upper
-  // layer (HttpNetworkTransaction) needs to handle a persistent connection
-  // closed by the server when we send a request anyway, a false positive in
-  // exchange for simpler code is a good trade-off.
-  EnterFunction("");
-  bool ret = (pseudo_connected_ || completed_handshake_) &&
-             transport_->socket()->IsConnected();
-  LeaveFunction("");
-  return ret;
-}
-
-bool SSLClientSocketNSS::IsConnectedAndIdle() const {
-  // Unlike IsConnected, this method doesn't return a false positive.
-  //
-  // Strictly speaking, we should check if we have received the close_notify
-  // alert message from the server, and return false in that case.  Although
-  // the close_notify alert message means EOF in the SSL layer, it is just
-  // bytes to the transport layer below, so
-  // transport_->socket()->IsConnectedAndIdle() returns the desired false
-  // when we receive close_notify.
-  EnterFunction("");
-  bool ret = (pseudo_connected_ || completed_handshake_) &&
-             transport_->socket()->IsConnectedAndIdle();
-  LeaveFunction("");
-  return ret;
-}
-
-int SSLClientSocketNSS::GetPeerAddress(AddressList* address) const {
-  return transport_->socket()->GetPeerAddress(address);
-}
-
-const BoundNetLog& SSLClientSocketNSS::NetLog() const {
-  return net_log_;
-}
-
-void SSLClientSocketNSS::SetSubresourceSpeculation() {
-  if (transport_.get() && transport_->socket()) {
-    transport_->socket()->SetSubresourceSpeculation();
-  } else {
-    NOTREACHED();
-  }
-}
-
-void SSLClientSocketNSS::SetOmniboxSpeculation() {
-  if (transport_.get() && transport_->socket()) {
-    transport_->socket()->SetOmniboxSpeculation();
-  } else {
-    NOTREACHED();
-  }
-}
-
-bool SSLClientSocketNSS::WasEverUsed() const {
-  if (transport_.get() && transport_->socket()) {
-    return transport_->socket()->WasEverUsed();
-  }
-  NOTREACHED();
-  return false;
-}
-
-bool SSLClientSocketNSS::UsingTCPFastOpen() const {
-  if (transport_.get() && transport_->socket()) {
-    return transport_->socket()->UsingTCPFastOpen();
-  }
-  NOTREACHED();
-  return false;
-}
-
-int SSLClientSocketNSS::Read(IOBuffer* buf, int buf_len,
-                             CompletionCallback* callback) {
-  EnterFunction(buf_len);
-  DCHECK(!user_read_callback_);
-  DCHECK(!user_connect_callback_);
-  DCHECK(!user_read_buf_);
-  DCHECK(nss_bufs_);
-
-  user_read_buf_ = buf;
-  user_read_buf_len_ = buf_len;
-
-  if (!completed_handshake_) {
-    // In this case we have lied about being connected in order to merge the
-    // first Write into a Snap Start handshake. We'll leave the read hanging
-    // until the handshake has completed.
-    DCHECK(pseudo_connected_);
-
-    user_read_callback_ = callback;
-    LeaveFunction(ERR_IO_PENDING);
-    return ERR_IO_PENDING;
-  }
-
-  int rv = DoReadLoop(OK);
-
-  if (rv == ERR_IO_PENDING) {
-    user_read_callback_ = callback;
-  } else {
-    user_read_buf_ = NULL;
-    user_read_buf_len_ = 0;
-  }
-  LeaveFunction(rv);
-  return rv;
-}
-
-int SSLClientSocketNSS::Write(IOBuffer* buf, int buf_len,
-                              CompletionCallback* callback) {
-  EnterFunction(buf_len);
-  if (!pseudo_connected_) {
-    DCHECK(completed_handshake_);
-    DCHECK(next_handshake_state_ == STATE_NONE);
-    DCHECK(!user_connect_callback_);
-  }
-  DCHECK(!user_write_callback_);
-  DCHECK(!user_write_buf_);
-  DCHECK(nss_bufs_);
-
-  user_write_buf_ = buf;
-  user_write_buf_len_ = buf_len;
-
-  if (next_handshake_state_ == STATE_SNAP_START_WAIT_FOR_WRITE) {
-    // We lied about being connected and we have been waiting for this write in
-    // order to merge it into the Snap Start handshake. We'll leave the write
-    // pending until the handshake completes.
-    DCHECK(pseudo_connected_);
-    int rv = DoHandshakeLoop(OK);
-    if (rv == ERR_IO_PENDING) {
-      user_write_callback_ = callback;
-    } else {
-      user_write_buf_ = NULL;
-      user_write_buf_len_ = 0;
-    }
-    if (rv != OK)
-      return rv;
-  }
-
-  if (corked_) {
-    corked_ = false;
-    uncork_timer_.Reset();
-  }
-  int rv = DoWriteLoop(OK);
-
-  if (rv == ERR_IO_PENDING) {
-    user_write_callback_ = callback;
-  } else {
-    user_write_buf_ = NULL;
-    user_write_buf_len_ = 0;
-  }
-  LeaveFunction(rv);
-  return rv;
-}
-
-bool SSLClientSocketNSS::SetReceiveBufferSize(int32 size) {
-  return transport_->socket()->SetReceiveBufferSize(size);
-}
-
-bool SSLClientSocketNSS::SetSendBufferSize(int32 size) {
-  return transport_->socket()->SetSendBufferSize(size);
-}
-
-// static
-void SSLClientSocketNSS::ClearSessionCache() {
-  SSL_ClearSessionCache();
-}
 
 // Sets server_cert_ and server_cert_nss_ if not yet set.
 // Returns server_cert_.
@@ -1051,91 +1159,6 @@
     ssl_connection_status_ |= SSL_CONNECTION_SSL3_FALLBACK;
 }
 
-void SSLClientSocketNSS::GetSSLInfo(SSLInfo* ssl_info) {
-  EnterFunction("");
-  ssl_info->Reset();
-
-  if (!server_cert_) {
-    LOG(DFATAL) << "!server_cert_";
-    return;
-  }
-
-  ssl_info->cert_status = server_cert_verify_result_->cert_status;
-  DCHECK(server_cert_ != NULL);
-  ssl_info->cert = server_cert_;
-  ssl_info->connection_status = ssl_connection_status_;
-
-  PRUint16 cipher_suite =
-      SSLConnectionStatusToCipherSuite(ssl_connection_status_);
-  SSLCipherSuiteInfo cipher_info;
-  SECStatus ok = SSL_GetCipherSuiteInfo(cipher_suite,
-                                        &cipher_info, sizeof(cipher_info));
-  if (ok == SECSuccess) {
-    ssl_info->security_bits = cipher_info.effectiveKeyBits;
-  } else {
-    ssl_info->security_bits = -1;
-    LOG(DFATAL) << "SSL_GetCipherSuiteInfo returned " << PR_GetError()
-                << " for cipherSuite " << cipher_suite;
-  }
-  LeaveFunction("");
-}
-
-void SSLClientSocketNSS::GetSSLCertRequestInfo(
-    SSLCertRequestInfo* cert_request_info) {
-  EnterFunction("");
-  // TODO(rch): switch SSLCertRequestInfo.host_and_port to a HostPortPair
-  cert_request_info->host_and_port = host_and_port_.ToString();
-  cert_request_info->client_certs = client_certs_;
-  LeaveFunction(cert_request_info->client_certs.size());
-}
-
-SSLClientSocket::NextProtoStatus
-SSLClientSocketNSS::GetNextProto(std::string* proto) {
-#if defined(SSL_NEXT_PROTO_NEGOTIATED)
-  if (!handshake_callback_called_) {
-    DCHECK(pseudo_connected_);
-    predicted_npn_proto_used_ = true;
-    *proto = predicted_npn_proto_;
-    return predicted_npn_status_;
-  }
-
-  unsigned char buf[255];
-  int state;
-  unsigned len;
-  SECStatus rv = SSL_GetNextProto(nss_fd_, &state, buf, &len, sizeof(buf));
-  if (rv != SECSuccess) {
-    NOTREACHED() << "Error return from SSL_GetNextProto: " << rv;
-    proto->clear();
-    return kNextProtoUnsupported;
-  }
-  // We don't check for truncation because sizeof(buf) is large enough to hold
-  // the maximum protocol size.
-  switch (state) {
-    case SSL_NEXT_PROTO_NO_SUPPORT:
-      proto->clear();
-      return kNextProtoUnsupported;
-    case SSL_NEXT_PROTO_NEGOTIATED:
-      *proto = std::string(reinterpret_cast<char*>(buf), len);
-      return kNextProtoNegotiated;
-    case SSL_NEXT_PROTO_NO_OVERLAP:
-      *proto = std::string(reinterpret_cast<char*>(buf), len);
-      return kNextProtoNoOverlap;
-    default:
-      NOTREACHED() << "Unknown status from SSL_GetNextProto: " << state;
-      proto->clear();
-      return kNextProtoUnsupported;
-  }
-#else
-  // No NPN support in the libssl that we are building with.
-  proto->clear();
-  return kNextProtoUnsupported;
-#endif
-}
-
-void SSLClientSocketNSS::UseDNSSEC(DNSSECProvider* provider) {
-  dnssec_provider_ = provider;
-}
-
 void SSLClientSocketNSS::DoReadCallback(int rv) {
   EnterFunction(rv);
   DCHECK(rv != ERR_IO_PENDING);
@@ -1250,109 +1273,6 @@
   LeaveFunction("");
 }
 
-// Do network I/O between the given buffer and the given socket.
-// Return true if some I/O performed, false otherwise (error or ERR_IO_PENDING)
-bool SSLClientSocketNSS::DoTransportIO() {
-  EnterFunction("");
-  bool network_moved = false;
-  if (nss_bufs_ != NULL) {
-    int nsent = BufferSend();
-    int nreceived = BufferRecv();
-    network_moved = (nsent > 0 || nreceived >= 0);
-  }
-  LeaveFunction(network_moved);
-  return network_moved;
-}
-
-// Return 0 for EOF,
-// > 0 for bytes transferred immediately,
-// < 0 for error (or the non-error ERR_IO_PENDING).
-int SSLClientSocketNSS::BufferSend(void) {
-  if (transport_send_busy_)
-    return ERR_IO_PENDING;
-
-  EnterFunction("");
-  const char* buf1;
-  const char* buf2;
-  unsigned int len1, len2;
-  memio_GetWriteParams(nss_bufs_, &buf1, &len1, &buf2, &len2);
-  const unsigned int len = len1 + len2;
-
-  if (corked_ && len < kRecvBufferSize / 2)
-    return 0;
-
-  int rv = 0;
-  if (len) {
-    scoped_refptr<IOBuffer> send_buffer(new IOBuffer(len));
-    memcpy(send_buffer->data(), buf1, len1);
-    memcpy(send_buffer->data() + len1, buf2, len2);
-    rv = transport_->socket()->Write(send_buffer, len,
-                                     &buffer_send_callback_);
-    if (rv == ERR_IO_PENDING) {
-      transport_send_busy_ = true;
-    } else {
-      memio_PutWriteResult(nss_bufs_, MapErrorToNSS(rv));
-    }
-  }
-
-  LeaveFunction(rv);
-  return rv;
-}
-
-void SSLClientSocketNSS::BufferSendComplete(int result) {
-  EnterFunction(result);
-
-  // In the case of TCP FastOpen, connect is now finished.
-  if (!peername_initialized_ && UsingTCPFastOpen())
-    InitializeSSLPeerName();
-
-  memio_PutWriteResult(nss_bufs_, MapErrorToNSS(result));
-  transport_send_busy_ = false;
-  OnSendComplete(result);
-  LeaveFunction("");
-}
-
-
-int SSLClientSocketNSS::BufferRecv(void) {
-  if (transport_recv_busy_) return ERR_IO_PENDING;
-
-  char *buf;
-  int nb = memio_GetReadParams(nss_bufs_, &buf);
-  EnterFunction(nb);
-  int rv;
-  if (!nb) {
-    // buffer too full to read into, so no I/O possible at moment
-    rv = ERR_IO_PENDING;
-  } else {
-    recv_buffer_ = new IOBuffer(nb);
-    rv = transport_->socket()->Read(recv_buffer_, nb, &buffer_recv_callback_);
-    if (rv == ERR_IO_PENDING) {
-      transport_recv_busy_ = true;
-    } else {
-      if (rv > 0)
-        memcpy(buf, recv_buffer_->data(), rv);
-      memio_PutReadResult(nss_bufs_, MapErrorToNSS(rv));
-      recv_buffer_ = NULL;
-    }
-  }
-  LeaveFunction(rv);
-  return rv;
-}
-
-void SSLClientSocketNSS::BufferRecvComplete(int result) {
-  EnterFunction(result);
-  if (result > 0) {
-    char *buf;
-    memio_GetReadParams(nss_bufs_, &buf);
-    memcpy(buf, recv_buffer_->data(), result);
-  }
-  recv_buffer_ = NULL;
-  memio_PutReadResult(nss_bufs_, MapErrorToNSS(result));
-  transport_recv_busy_ = false;
-  OnRecvComplete(result);
-  LeaveFunction("");
-}
-
 int SSLClientSocketNSS::DoHandshakeLoop(int last_io_result) {
   EnterFunction(last_io_result);
   bool network_moved;
@@ -1459,6 +1379,700 @@
   return rv;
 }
 
+int SSLClientSocketNSS::DoSnapStartLoadInfo() {
+  EnterFunction("");
+  int rv = ssl_host_info_->WaitForDataReady(&handshake_io_callback_);
+  GotoState(STATE_HANDSHAKE);
+
+  if (rv == OK) {
+    if (ssl_host_info_->WaitForCertVerification(NULL) == OK) {
+      if (LoadSnapStartInfo()) {
+        pseudo_connected_ = true;
+        GotoState(STATE_SNAP_START_WAIT_FOR_WRITE);
+        if (user_connect_callback_)
+          DoConnectCallback(OK);
+      }
+    } else if (!ssl_host_info_->state().server_hello.empty()) {
+      // A non-empty ServerHello suggests that we would have tried a Snap Start
+      // connection.
+      base::TimeTicks now = base::TimeTicks::Now();
+      const base::TimeDelta duration =
+          now - ssl_host_info_->verification_start_time();
+      UMA_HISTOGRAM_TIMES("Net.SSLSnapStartNeededVerificationInMs", duration);
+      VLOG(1) << "Cannot snap start because verification isn't ready. "
+              << "Wanted verification after "
+              << duration.InMilliseconds() << "ms";
+    }
+  } else {
+    DCHECK_EQ(ERR_IO_PENDING, rv);
+    GotoState(STATE_SNAP_START_LOAD_INFO);
+  }
+
+  LeaveFunction("");
+  return rv;
+}
+
+int SSLClientSocketNSS::DoSnapStartWaitForWrite() {
+  EnterFunction("");
+  // In this state, we're waiting for the first Write call so that we can merge
+  // it into the Snap Start handshake.
+  if (!user_write_buf_) {
+    // We'll lie and say that we're connected in order that someone will call
+    // Write.
+    GotoState(STATE_SNAP_START_WAIT_FOR_WRITE);
+    DCHECK(!user_connect_callback_);
+    LeaveFunction("");
+    return ERR_IO_PENDING;
+  }
+
+  // This is the largest Snap Start application data payload that we'll try to
+  // use. A TCP client can only send three frames of data without an ACK and,
+  // at 2048 bytes, this leaves some space for the rest of the ClientHello
+  // (including possible session ticket).
+  static const int kMaxSnapStartPayloadSize = 2048;
+
+  if (user_write_buf_len_ > kMaxSnapStartPayloadSize) {
+    user_write_buf_len_ = kMaxSnapStartPayloadSize;
+    // When we complete the handshake and call user_write_callback_ we'll say
+    // that we only wrote |kMaxSnapStartPayloadSize| bytes. That way the rest
+    // of the payload will be presented to |Write| again and transmitted as
+    // normal application data.
+  }
+
+  SECStatus rv = SSL_SetSnapStartApplicationData(
+      nss_fd_, reinterpret_cast<const unsigned char*>(user_write_buf_->data()),
+      user_write_buf_len_);
+  DCHECK_EQ(SECSuccess, rv);
+
+  GotoState(STATE_HANDSHAKE);
+  LeaveFunction("");
+  return OK;
+}
+
+int SSLClientSocketNSS::DoHandshake() {
+  EnterFunction("");
+  int net_error = net::OK;
+  SECStatus rv = SSL_ForceHandshake(nss_fd_);
+
+  if (client_auth_cert_needed_) {
+    net_error = ERR_SSL_CLIENT_AUTH_CERT_NEEDED;
+    net_log_.AddEvent(NetLog::TYPE_SSL_HANDSHAKE_ERROR,
+                      make_scoped_refptr(new SSLErrorParams(net_error, 0)));
+    // If the handshake already succeeded (because the server requests but
+    // doesn't require a client cert), we need to invalidate the SSL session
+    // so that we won't try to resume the non-client-authenticated session in
+    // the next handshake.  This will cause the server to ask for a client
+    // cert again.
+    if (rv == SECSuccess && SSL_InvalidateSession(nss_fd_) != SECSuccess) {
+      LOG(WARNING) << "Couldn't invalidate SSL session: " << PR_GetError();
+    }
+  } else if (rv == SECSuccess) {
+    if (handshake_callback_called_) {
+      if (eset_mitm_detected_) {
+        net_error = ERR_ESET_ANTI_VIRUS_SSL_INTERCEPTION;
+      } else {
+        // We need to see if the predicted certificate chain (in
+        // |ssl_host_info_->state().certs) matches the actual certificate chain
+        // before we call SaveSnapStartInfo, as that will update
+        // |ssl_host_info_|.
+        if (ssl_host_info_.get() && !ssl_host_info_->state().certs.empty()) {
+          PeerCertificateChain certs(nss_fd_);
+          const SSLHostInfo::State& state = ssl_host_info_->state();
+          predicted_cert_chain_correct_ = certs.size() == state.certs.size();
+          if (predicted_cert_chain_correct_) {
+            for (unsigned i = 0; i < certs.size(); i++) {
+              if (certs[i]->derCert.len != state.certs[i].size() ||
+                  memcmp(certs[i]->derCert.data, state.certs[i].data(),
+                         certs[i]->derCert.len) != 0) {
+                predicted_cert_chain_correct_ = false;
+                break;
+              }
+            }
+          }
+        }
+
+#if defined(SSL_ENABLE_OCSP_STAPLING)
+        const CacheOCSPResponseFromSideChannelFunction cache_ocsp_response =
+            GetCacheOCSPResponseFromSideChannelFunction();
+        // TODO: we need to be able to plumb an OCSP response into the system
+        // libraries. When we do, GetOCSPResponseFromSideChannelFunction
+        // needs to be updated for those platforms.
+        if (!predicted_cert_chain_correct_ && cache_ocsp_response) {
+          unsigned int len = 0;
+          SSL_GetStapledOCSPResponse(nss_fd_, NULL, &len);
+          if (len) {
+            const unsigned int orig_len = len;
+            scoped_array<uint8> ocsp_response(new uint8[orig_len]);
+            SSL_GetStapledOCSPResponse(nss_fd_, ocsp_response.get(), &len);
+            DCHECK_EQ(orig_len, len);
+
+            SECItem ocsp_response_item;
+            ocsp_response_item.type = siBuffer;
+            ocsp_response_item.data = ocsp_response.get();
+            ocsp_response_item.len = len;
+
+            cache_ocsp_response(
+                CERT_GetDefaultCertDB(), server_cert_nss_, PR_Now(),
+                &ocsp_response_item, NULL);
+          }
+        }
+#endif
+
+        SaveSnapStartInfo();
+        // SSL handshake is completed. It's possible that we mispredicted the
+        // NPN agreed protocol. In this case, we've just sent a request in the
+        // wrong protocol! The higher levels of this network stack aren't
+        // prepared for switching the protocol like that so we make up an error
+        // and rely on the fact that the request will be retried.
+        if (IsNPNProtocolMispredicted()) {
+          LOG(WARNING) << "Mispredicted NPN protocol for "
+                       << host_and_port_.ToString();
+          net_error = ERR_SSL_SNAP_START_NPN_MISPREDICTION;
+        } else {
+          // Let's verify the certificate.
+          GotoState(STATE_VERIFY_DNSSEC);
+        }
+      }
+      // Done!
+    } else {
+      // Workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=562434 -
+      // SSL_ForceHandshake returned SECSuccess prematurely.
+      rv = SECFailure;
+      net_error = ERR_SSL_PROTOCOL_ERROR;
+      net_log_.AddEvent(NetLog::TYPE_SSL_HANDSHAKE_ERROR,
+                        make_scoped_refptr(new SSLErrorParams(net_error, 0)));
+    }
+  } else {
+    PRErrorCode prerr = PR_GetError();
+    net_error = MapNSSHandshakeError(prerr);
+
+    // If not done, stay in this state
+    if (net_error == ERR_IO_PENDING) {
+      GotoState(STATE_HANDSHAKE);
+    } else {
+      LOG(ERROR) << "handshake failed; NSS error code " << prerr
+                 << ", net_error " << net_error;
+      net_log_.AddEvent(
+          NetLog::TYPE_SSL_HANDSHAKE_ERROR,
+          make_scoped_refptr(new SSLErrorParams(net_error, prerr)));
+    }
+  }
+
+  LeaveFunction("");
+  return net_error;
+}
+
+int SSLClientSocketNSS::DoVerifyDNSSEC(int result) {
+  if (ssl_config_.dns_cert_provenance_checking_enabled &&
+      dns_cert_checker_) {
+    PeerCertificateChain certs(nss_fd_);
+    dns_cert_checker_->DoAsyncVerification(
+        host_and_port_.host(), certs.AsStringPieceVector());
+  }
+
+  if (ssl_config_.dnssec_enabled) {
+    DNSValidationResult r = CheckDNSSECChain(host_and_port_.host(),
+                                             server_cert_nss_);
+    if (r == DNSVR_SUCCESS) {
+      local_server_cert_verify_result_.cert_status |= CERT_STATUS_IS_DNSSEC;
+      server_cert_verify_result_ = &local_server_cert_verify_result_;
+      GotoState(STATE_VERIFY_CERT_COMPLETE);
+      return OK;
+    }
+  }
+
+  if (dnssec_provider_ == NULL) {
+    GotoState(STATE_VERIFY_CERT);
+    return OK;
+  }
+
+  GotoState(STATE_VERIFY_DNSSEC_COMPLETE);
+  RRResponse* response;
+  dnssec_wait_start_time_ = base::Time::Now();
+  return dnssec_provider_->GetDNSSECRecords(&response, &handshake_io_callback_);
+}
+
+int SSLClientSocketNSS::DoVerifyDNSSECComplete(int result) {
+  RRResponse* response;
+  int err = dnssec_provider_->GetDNSSECRecords(&response, NULL);
+  DCHECK_EQ(err, OK);
+
+  const base::TimeDelta elapsed = base::Time::Now() - dnssec_wait_start_time_;
+  HISTOGRAM_TIMES("Net.DNSSECWaitTime", elapsed);
+
+  GotoState(STATE_VERIFY_CERT);
+  if (!response || response->rrdatas.empty())
+    return OK;
+
+  std::vector<base::StringPiece> records;
+  records.resize(response->rrdatas.size());
+  for (unsigned i = 0; i < response->rrdatas.size(); i++)
+    records[i] = base::StringPiece(response->rrdatas[i]);
+  DNSValidationResult r =
+      VerifyTXTRecords(response->dnssec, server_cert_nss_, records);
+
+  if (!ssl_config_.dnssec_enabled) {
+    // If DNSSEC is not enabled we don't take any action based on the result,
+    // except to record the latency, above.
+    return OK;
+  }
+
+  switch (r) {
+    case DNSVR_FAILURE:
+      GotoState(STATE_VERIFY_CERT_COMPLETE);
+      local_server_cert_verify_result_.cert_status |= CERT_STATUS_NOT_IN_DNS;
+      server_cert_verify_result_ = &local_server_cert_verify_result_;
+      return ERR_CERT_NOT_IN_DNS;
+    case DNSVR_CONTINUE:
+      GotoState(STATE_VERIFY_CERT);
+      break;
+    case DNSVR_SUCCESS:
+      local_server_cert_verify_result_.cert_status |= CERT_STATUS_IS_DNSSEC;
+      server_cert_verify_result_ = &local_server_cert_verify_result_;
+      GotoState(STATE_VERIFY_CERT_COMPLETE);
+      break;
+    default:
+      NOTREACHED();
+      GotoState(STATE_VERIFY_CERT);
+  }
+
+  return OK;
+}
+
+int SSLClientSocketNSS::DoVerifyCert(int result) {
+  DCHECK(server_cert_);
+
+  GotoState(STATE_VERIFY_CERT_COMPLETE);
+  start_cert_verification_time_ = base::TimeTicks::Now();
+
+  if (ssl_host_info_.get() && !ssl_host_info_->state().certs.empty() &&
+      predicted_cert_chain_correct_) {
+    // If the SSLHostInfo had a prediction for the certificate chain of this
+    // server then it will have optimistically started a verification of that
+    // chain. So, if the prediction was correct, we should wait for that
+    // verification to finish rather than start our own.
+    net_log_.AddEvent(NetLog::TYPE_SSL_VERIFICATION_MERGED, NULL);
+    UMA_HISTOGRAM_ENUMERATION("Net.SSLVerificationMerged", 1 /* true */, 2);
+    base::TimeTicks end_time = ssl_host_info_->verification_end_time();
+    if (end_time.is_null())
+      end_time = base::TimeTicks::Now();
+    UMA_HISTOGRAM_TIMES("Net.SSLVerificationMergedMsSaved",
+                        end_time - ssl_host_info_->verification_start_time());
+    server_cert_verify_result_ = &ssl_host_info_->cert_verify_result();
+    return ssl_host_info_->WaitForCertVerification(&handshake_io_callback_);
+  } else {
+    UMA_HISTOGRAM_ENUMERATION("Net.SSLVerificationMerged", 0 /* false */, 2);
+  }
+
+  int flags = 0;
+  if (ssl_config_.rev_checking_enabled)
+    flags |= X509Certificate::VERIFY_REV_CHECKING_ENABLED;
+  if (ssl_config_.verify_ev_cert)
+    flags |= X509Certificate::VERIFY_EV_CERT;
+  verifier_.reset(new SingleRequestCertVerifier(cert_verifier_));
+  server_cert_verify_result_ = &local_server_cert_verify_result_;
+  return verifier_->Verify(server_cert_, host_and_port_.host(), flags,
+                           &local_server_cert_verify_result_,
+                           &handshake_io_callback_);
+}
+
+// Derived from AuthCertificateCallback() in
+// mozilla/source/security/manager/ssl/src/nsNSSCallbacks.cpp.
+int SSLClientSocketNSS::DoVerifyCertComplete(int result) {
+  verifier_.reset();
+
+  if (!start_cert_verification_time_.is_null()) {
+    base::TimeDelta verify_time =
+        base::TimeTicks::Now() - start_cert_verification_time_;
+    if (result == OK)
+        UMA_HISTOGRAM_TIMES("Net.SSLCertVerificationTime", verify_time);
+    else
+        UMA_HISTOGRAM_TIMES("Net.SSLCertVerificationTimeError", verify_time);
+  }
+
+  if (ssl_host_info_.get())
+    ssl_host_info_->set_cert_verification_finished_time();
+
+  // We used to remember the intermediate CA certs in the NSS database
+  // persistently.  However, NSS opens a connection to the SQLite database
+  // during NSS initialization and doesn't close the connection until NSS
+  // shuts down.  If the file system where the database resides is gone,
+  // the database connection goes bad.  What's worse, the connection won't
+  // recover when the file system comes back.  Until this NSS or SQLite bug
+  // is fixed, we need to  avoid using the NSS database for non-essential
+  // purposes.  See https://bugzilla.mozilla.org/show_bug.cgi?id=508081 and
+  // http://crbug.com/15630 for more info.
+
+  // If we have been explicitly told to accept this certificate, override the
+  // result of verifier_.Verify.
+  // Eventually, we should cache the cert verification results so that we don't
+  // need to call verifier_.Verify repeatedly.  But for now we need to do this.
+  // Alternatively, we could use the cert's status that we stored along with
+  // the cert in the allowed_bad_certs vector.
+  if (IsCertificateError(result) &&
+      ssl_config_.IsAllowedBadCert(server_cert_)) {
+    VLOG(1) << "accepting bad SSL certificate, as user told us to";
+    result = OK;
+  }
+
+  if (result == OK)
+    LogConnectionTypeMetrics();
+
+  completed_handshake_ = true;
+
+  // If we merged a Write call into the handshake we need to make the
+  // callback now.
+  if (user_write_callback_) {
+    corked_ = false;
+    if (result != OK) {
+      DoWriteCallback(result);
+    } else {
+      SSLSnapStartResult snap_start_type;
+      SECStatus rv = SSL_GetSnapStartResult(nss_fd_, &snap_start_type);
+      DCHECK_EQ(rv, SECSuccess);
+      DCHECK_NE(snap_start_type, SSL_SNAP_START_NONE);
+      if (snap_start_type == SSL_SNAP_START_RECOVERY ||
+          snap_start_type == SSL_SNAP_START_RESUME_RECOVERY) {
+        // If we mispredicted the server's handshake then Snap Start will have
+        // triggered a recovery mode. The misprediction could have been caused
+        // by the server having a different certificate so the application data
+        // wasn't resent. Now that we have verified the certificate, we need to
+        // resend the application data.
+        int bytes_written = DoPayloadWrite();
+        if (bytes_written != ERR_IO_PENDING)
+          DoWriteCallback(bytes_written);
+      } else {
+        DoWriteCallback(user_write_buf_len_);
+      }
+    }
+  }
+
+  if (user_read_callback_) {
+    int rv = DoReadLoop(OK);
+    if (rv != ERR_IO_PENDING)
+      DoReadCallback(rv);
+  }
+
+  // Exit DoHandshakeLoop and return the result to the caller to Connect.
+  DCHECK(next_handshake_state_ == STATE_NONE);
+  return result;
+}
+
+int SSLClientSocketNSS::DoPayloadRead() {
+  EnterFunction(user_read_buf_len_);
+  DCHECK(user_read_buf_);
+  DCHECK_GT(user_read_buf_len_, 0);
+  int rv = PR_Read(nss_fd_, user_read_buf_->data(), user_read_buf_len_);
+  if (client_auth_cert_needed_) {
+    // We don't need to invalidate the non-client-authenticated SSL session
+    // because the server will renegotiate anyway.
+    LeaveFunction("");
+    rv = ERR_SSL_CLIENT_AUTH_CERT_NEEDED;
+    net_log_.AddEvent(NetLog::TYPE_SSL_READ_ERROR,
+                      make_scoped_refptr(new SSLErrorParams(rv, 0)));
+    return rv;
+  }
+  if (rv >= 0) {
+    LogData(user_read_buf_->data(), rv);
+    LeaveFunction("");
+    return rv;
+  }
+  PRErrorCode prerr = PR_GetError();
+  if (prerr == PR_WOULD_BLOCK_ERROR) {
+    LeaveFunction("");
+    return ERR_IO_PENDING;
+  }
+  LeaveFunction("");
+  rv = MapNSSError(prerr);
+  net_log_.AddEvent(NetLog::TYPE_SSL_READ_ERROR,
+                    make_scoped_refptr(new SSLErrorParams(rv, prerr)));
+  return rv;
+}
+
+int SSLClientSocketNSS::DoPayloadWrite() {
+  EnterFunction(user_write_buf_len_);
+  DCHECK(user_write_buf_);
+  int rv = PR_Write(nss_fd_, user_write_buf_->data(), user_write_buf_len_);
+  if (rv >= 0) {
+    LogData(user_write_buf_->data(), rv);
+    LeaveFunction("");
+    return rv;
+  }
+  PRErrorCode prerr = PR_GetError();
+  if (prerr == PR_WOULD_BLOCK_ERROR) {
+    LeaveFunction("");
+    return ERR_IO_PENDING;
+  }
+  LeaveFunction("");
+  rv = MapNSSError(prerr);
+  net_log_.AddEvent(NetLog::TYPE_SSL_WRITE_ERROR,
+                    make_scoped_refptr(new SSLErrorParams(rv, prerr)));
+  return rv;
+}
+
+void SSLClientSocketNSS::LogConnectionTypeMetrics() const {
+  UpdateConnectionTypeHistograms(CONNECTION_SSL);
+  if (server_cert_verify_result_->has_md5)
+    UpdateConnectionTypeHistograms(CONNECTION_SSL_MD5);
+  if (server_cert_verify_result_->has_md2)
+    UpdateConnectionTypeHistograms(CONNECTION_SSL_MD2);
+  if (server_cert_verify_result_->has_md4)
+    UpdateConnectionTypeHistograms(CONNECTION_SSL_MD4);
+  if (server_cert_verify_result_->has_md5_ca)
+    UpdateConnectionTypeHistograms(CONNECTION_SSL_MD5_CA);
+  if (server_cert_verify_result_->has_md2_ca)
+    UpdateConnectionTypeHistograms(CONNECTION_SSL_MD2_CA);
+  int ssl_version = SSLConnectionStatusToVersion(ssl_connection_status_);
+  switch (ssl_version) {
+    case SSL_CONNECTION_VERSION_SSL2:
+      UpdateConnectionTypeHistograms(CONNECTION_SSL_SSL2);
+      break;
+    case SSL_CONNECTION_VERSION_SSL3:
+      UpdateConnectionTypeHistograms(CONNECTION_SSL_SSL3);
+      break;
+    case SSL_CONNECTION_VERSION_TLS1:
+      UpdateConnectionTypeHistograms(CONNECTION_SSL_TLS1);
+      break;
+    case SSL_CONNECTION_VERSION_TLS1_1:
+      UpdateConnectionTypeHistograms(CONNECTION_SSL_TLS1_1);
+      break;
+    case SSL_CONNECTION_VERSION_TLS1_2:
+      UpdateConnectionTypeHistograms(CONNECTION_SSL_TLS1_2);
+      break;
+  };
+}
+
+// SaveSnapStartInfo extracts the information needed to perform a Snap Start
+// with this server in the future (if any) and tells |ssl_host_info_| to
+// preserve it.
+void SSLClientSocketNSS::SaveSnapStartInfo() {
+  if (!ssl_host_info_.get())
+    return;
+
+  // If the SSLHostInfo hasn't managed to load from disk yet then we can't save
+  // anything.
+  if (ssl_host_info_->WaitForDataReady(NULL) != OK)
+    return;
+
+  SECStatus rv;
+  SSLSnapStartResult snap_start_type;
+  rv = SSL_GetSnapStartResult(nss_fd_, &snap_start_type);
+  if (rv != SECSuccess) {
+    NOTREACHED();
+    return;
+  }
+  net_log_.AddEvent(NetLog::TYPE_SSL_SNAP_START,
+                    new NetLogIntegerParameter("type", snap_start_type));
+  if (snap_start_type == SSL_SNAP_START_FULL ||
+      snap_start_type == SSL_SNAP_START_RESUME) {
+    // If we did a successful Snap Start then our information was correct and
+    // there's no point saving it again.
+    return;
+  }
+
+  const unsigned char* hello_data;
+  unsigned hello_data_len;
+  rv = SSL_GetPredictedServerHelloData(nss_fd_, &hello_data, &hello_data_len);
+  if (rv != SECSuccess) {
+    NOTREACHED();
+    return;
+  }
+  if (hello_data_len > std::numeric_limits<uint16>::max())
+    return;
+  SSLHostInfo::State* state = ssl_host_info_->mutable_state();
+
+  if (hello_data_len > 0) {
+    state->server_hello =
+        std::string(reinterpret_cast<const char *>(hello_data), hello_data_len);
+    state->npn_valid = true;
+    state->npn_status = GetNextProto(&state->npn_protocol);
+  } else {
+    state->server_hello.clear();
+    state->npn_valid = false;
+  }
+
+  state->certs.clear();
+  PeerCertificateChain certs(nss_fd_);
+  for (unsigned i = 0; i < certs.size(); i++) {
+    if (certs[i]->derCert.len > std::numeric_limits<uint16>::max())
+      return;
+
+    state->certs.push_back(std::string(
+          reinterpret_cast<char*>(certs[i]->derCert.data),
+          certs[i]->derCert.len));
+  }
+
+  ssl_host_info_->Persist();
+}
+
+// LoadSnapStartInfo parses |info|, which contains data previously serialised
+// by |SaveSnapStartInfo|, and sets the predicted certificates and ServerHello
+// data on the NSS socket. Returns true on success. If this function returns
+// false, the caller should try a normal TLS handshake.
+bool SSLClientSocketNSS::LoadSnapStartInfo() {
+  const SSLHostInfo::State& state(ssl_host_info_->state());
+
+  if (state.server_hello.empty() ||
+      state.certs.empty() ||
+      !state.npn_valid) {
+    return false;
+  }
+
+  SECStatus rv;
+  rv = SSL_SetPredictedServerHelloData(
+      nss_fd_,
+      reinterpret_cast<const uint8*>(state.server_hello.data()),
+      state.server_hello.size());
+  DCHECK_EQ(SECSuccess, rv);
+
+  const std::vector<std::string>& certs_in = state.certs;
+  scoped_array<CERTCertificate*> certs(new CERTCertificate*[certs_in.size()]);
+  for (size_t i = 0; i < certs_in.size(); i++) {
+    SECItem derCert;
+    derCert.data =
+        const_cast<uint8*>(reinterpret_cast<const uint8*>(certs_in[i].data()));
+    derCert.len = certs_in[i].size();
+    certs[i] = CERT_NewTempCertificate(
+        CERT_GetDefaultCertDB(), &derCert, NULL /* no nickname given */,
+        PR_FALSE /* not permanent */, PR_TRUE /* copy DER data */);
+    if (!certs[i]) {
+      DestroyCertificates(&certs[0], i);
+      NOTREACHED();
+      return false;
+    }
+  }
+
+  rv = SSL_SetPredictedPeerCertificates(nss_fd_, certs.get(), certs_in.size());
+  DestroyCertificates(&certs[0], certs_in.size());
+  DCHECK_EQ(SECSuccess, rv);
+
+  if (state.npn_valid) {
+    predicted_npn_status_ = state.npn_status;
+    predicted_npn_proto_ = state.npn_protocol;
+  }
+
+  return true;
+}
+
+bool SSLClientSocketNSS::IsNPNProtocolMispredicted() {
+  DCHECK(handshake_callback_called_);
+  if (!predicted_npn_proto_used_)
+    return false;
+  std::string npn_proto;
+  GetNextProto(&npn_proto);
+  return predicted_npn_proto_ != npn_proto;
+}
+
+void SSLClientSocketNSS::UncorkAfterTimeout() {
+  corked_ = false;
+  int nsent;
+  do {
+    nsent = BufferSend();
+  } while (nsent > 0);
+}
+
+// Do network I/O between the given buffer and the given socket.
+// Return true if some I/O performed, false otherwise (error or ERR_IO_PENDING)
+bool SSLClientSocketNSS::DoTransportIO() {
+  EnterFunction("");
+  bool network_moved = false;
+  if (nss_bufs_ != NULL) {
+    int nsent = BufferSend();
+    int nreceived = BufferRecv();
+    network_moved = (nsent > 0 || nreceived >= 0);
+  }
+  LeaveFunction(network_moved);
+  return network_moved;
+}
+
+// Return 0 for EOF,
+// > 0 for bytes transferred immediately,
+// < 0 for error (or the non-error ERR_IO_PENDING).
+int SSLClientSocketNSS::BufferSend(void) {
+  if (transport_send_busy_)
+    return ERR_IO_PENDING;
+
+  EnterFunction("");
+  const char* buf1;
+  const char* buf2;
+  unsigned int len1, len2;
+  memio_GetWriteParams(nss_bufs_, &buf1, &len1, &buf2, &len2);
+  const unsigned int len = len1 + len2;
+
+  if (corked_ && len < kRecvBufferSize / 2)
+    return 0;
+
+  int rv = 0;
+  if (len) {
+    scoped_refptr<IOBuffer> send_buffer(new IOBuffer(len));
+    memcpy(send_buffer->data(), buf1, len1);
+    memcpy(send_buffer->data() + len1, buf2, len2);
+    rv = transport_->socket()->Write(send_buffer, len,
+                                     &buffer_send_callback_);
+    if (rv == ERR_IO_PENDING) {
+      transport_send_busy_ = true;
+    } else {
+      memio_PutWriteResult(nss_bufs_, MapErrorToNSS(rv));
+    }
+  }
+
+  LeaveFunction(rv);
+  return rv;
+}
+
+void SSLClientSocketNSS::BufferSendComplete(int result) {
+  EnterFunction(result);
+
+  // In the case of TCP FastOpen, connect is now finished.
+  if (!peername_initialized_ && UsingTCPFastOpen())
+    InitializeSSLPeerName();
+
+  memio_PutWriteResult(nss_bufs_, MapErrorToNSS(result));
+  transport_send_busy_ = false;
+  OnSendComplete(result);
+  LeaveFunction("");
+}
+
+int SSLClientSocketNSS::BufferRecv(void) {
+  if (transport_recv_busy_) return ERR_IO_PENDING;
+
+  char *buf;
+  int nb = memio_GetReadParams(nss_bufs_, &buf);
+  EnterFunction(nb);
+  int rv;
+  if (!nb) {
+    // buffer too full to read into, so no I/O possible at moment
+    rv = ERR_IO_PENDING;
+  } else {
+    recv_buffer_ = new IOBuffer(nb);
+    rv = transport_->socket()->Read(recv_buffer_, nb, &buffer_recv_callback_);
+    if (rv == ERR_IO_PENDING) {
+      transport_recv_busy_ = true;
+    } else {
+      if (rv > 0)
+        memcpy(buf, recv_buffer_->data(), rv);
+      memio_PutReadResult(nss_bufs_, MapErrorToNSS(rv));
+      recv_buffer_ = NULL;
+    }
+  }
+  LeaveFunction(rv);
+  return rv;
+}
+
+void SSLClientSocketNSS::BufferRecvComplete(int result) {
+  EnterFunction(result);
+  if (result > 0) {
+    char *buf;
+    memio_GetReadParams(nss_bufs_, &buf);
+    memcpy(buf, recv_buffer_->data(), result);
+  }
+  recv_buffer_ = NULL;
+  memio_PutReadResult(nss_bufs_, MapErrorToNSS(result));
+  transport_recv_busy_ = false;
+  OnRecvComplete(result);
+  LeaveFunction("");
+}
+
 // static
 // NSS calls this if an incoming certificate needs to be verified.
 // Do nothing but return SECSuccess.
@@ -1900,619 +2514,4 @@
   that->UpdateConnectionStatus();
 }
 
-int SSLClientSocketNSS::DoSnapStartLoadInfo() {
-  EnterFunction("");
-  int rv = ssl_host_info_->WaitForDataReady(&handshake_io_callback_);
-  GotoState(STATE_HANDSHAKE);
-
-  if (rv == OK) {
-    if (ssl_host_info_->WaitForCertVerification(NULL) == OK) {
-      if (LoadSnapStartInfo()) {
-        pseudo_connected_ = true;
-        GotoState(STATE_SNAP_START_WAIT_FOR_WRITE);
-        if (user_connect_callback_)
-          DoConnectCallback(OK);
-      }
-    } else if (!ssl_host_info_->state().server_hello.empty()) {
-      // A non-empty ServerHello suggests that we would have tried a Snap Start
-      // connection.
-      base::TimeTicks now = base::TimeTicks::Now();
-      const base::TimeDelta duration =
-          now - ssl_host_info_->verification_start_time();
-      UMA_HISTOGRAM_TIMES("Net.SSLSnapStartNeededVerificationInMs", duration);
-      VLOG(1) << "Cannot snap start because verification isn't ready. "
-              << "Wanted verification after "
-              << duration.InMilliseconds() << "ms";
-    }
-  } else {
-    DCHECK_EQ(ERR_IO_PENDING, rv);
-    GotoState(STATE_SNAP_START_LOAD_INFO);
-  }
-
-  LeaveFunction("");
-  return rv;
-}
-
-int SSLClientSocketNSS::DoSnapStartWaitForWrite() {
-  EnterFunction("");
-  // In this state, we're waiting for the first Write call so that we can merge
-  // it into the Snap Start handshake.
-  if (!user_write_buf_) {
-    // We'll lie and say that we're connected in order that someone will call
-    // Write.
-    GotoState(STATE_SNAP_START_WAIT_FOR_WRITE);
-    DCHECK(!user_connect_callback_);
-    LeaveFunction("");
-    return ERR_IO_PENDING;
-  }
-
-  // This is the largest Snap Start application data payload that we'll try to
-  // use. A TCP client can only send three frames of data without an ACK and,
-  // at 2048 bytes, this leaves some space for the rest of the ClientHello
-  // (including possible session ticket).
-  static const int kMaxSnapStartPayloadSize = 2048;
-
-  if (user_write_buf_len_ > kMaxSnapStartPayloadSize) {
-    user_write_buf_len_ = kMaxSnapStartPayloadSize;
-    // When we complete the handshake and call user_write_callback_ we'll say
-    // that we only wrote |kMaxSnapStartPayloadSize| bytes. That way the rest
-    // of the payload will be presented to |Write| again and transmitted as
-    // normal application data.
-  }
-
-  SECStatus rv = SSL_SetSnapStartApplicationData(
-      nss_fd_, reinterpret_cast<const unsigned char*>(user_write_buf_->data()),
-      user_write_buf_len_);
-  DCHECK_EQ(SECSuccess, rv);
-
-  GotoState(STATE_HANDSHAKE);
-  LeaveFunction("");
-  return OK;
-}
-
-int SSLClientSocketNSS::DoHandshake() {
-  EnterFunction("");
-  int net_error = net::OK;
-  SECStatus rv = SSL_ForceHandshake(nss_fd_);
-
-  if (client_auth_cert_needed_) {
-    net_error = ERR_SSL_CLIENT_AUTH_CERT_NEEDED;
-    net_log_.AddEvent(NetLog::TYPE_SSL_HANDSHAKE_ERROR,
-                      make_scoped_refptr(new SSLErrorParams(net_error, 0)));
-    // If the handshake already succeeded (because the server requests but
-    // doesn't require a client cert), we need to invalidate the SSL session
-    // so that we won't try to resume the non-client-authenticated session in
-    // the next handshake.  This will cause the server to ask for a client
-    // cert again.
-    if (rv == SECSuccess && SSL_InvalidateSession(nss_fd_) != SECSuccess) {
-      LOG(WARNING) << "Couldn't invalidate SSL session: " << PR_GetError();
-    }
-  } else if (rv == SECSuccess) {
-    if (handshake_callback_called_) {
-      if (eset_mitm_detected_) {
-        net_error = ERR_ESET_ANTI_VIRUS_SSL_INTERCEPTION;
-      } else {
-        // We need to see if the predicted certificate chain (in
-        // |ssl_host_info_->state().certs) matches the actual certificate chain
-        // before we call SaveSnapStartInfo, as that will update
-        // |ssl_host_info_|.
-        if (ssl_host_info_.get() && !ssl_host_info_->state().certs.empty()) {
-          PeerCertificateChain certs(nss_fd_);
-          const SSLHostInfo::State& state = ssl_host_info_->state();
-          predicted_cert_chain_correct_ = certs.size() == state.certs.size();
-          if (predicted_cert_chain_correct_) {
-            for (unsigned i = 0; i < certs.size(); i++) {
-              if (certs[i]->derCert.len != state.certs[i].size() ||
-                  memcmp(certs[i]->derCert.data, state.certs[i].data(),
-                         certs[i]->derCert.len) != 0) {
-                predicted_cert_chain_correct_ = false;
-                break;
-              }
-            }
-          }
-        }
-
-#if defined(SSL_ENABLE_OCSP_STAPLING)
-        const CacheOCSPResponseFromSideChannelFunction cache_ocsp_response =
-            GetCacheOCSPResponseFromSideChannelFunction();
-        // TODO: we need to be able to plumb an OCSP response into the system
-        // libraries. When we do, GetOCSPResponseFromSideChannelFunction
-        // needs to be updated for those platforms.
-        if (!predicted_cert_chain_correct_ && cache_ocsp_response) {
-          unsigned int len = 0;
-          SSL_GetStapledOCSPResponse(nss_fd_, NULL, &len);
-          if (len) {
-            const unsigned int orig_len = len;
-            scoped_array<uint8> ocsp_response(new uint8[orig_len]);
-            SSL_GetStapledOCSPResponse(nss_fd_, ocsp_response.get(), &len);
-            DCHECK_EQ(orig_len, len);
-
-            SECItem ocsp_response_item;
-            ocsp_response_item.type = siBuffer;
-            ocsp_response_item.data = ocsp_response.get();
-            ocsp_response_item.len = len;
-
-            cache_ocsp_response(
-                CERT_GetDefaultCertDB(), server_cert_nss_, PR_Now(),
-                &ocsp_response_item, NULL);
-          }
-        }
-#endif
-
-        SaveSnapStartInfo();
-        // SSL handshake is completed. It's possible that we mispredicted the
-        // NPN agreed protocol. In this case, we've just sent a request in the
-        // wrong protocol! The higher levels of this network stack aren't
-        // prepared for switching the protocol like that so we make up an error
-        // and rely on the fact that the request will be retried.
-        if (IsNPNProtocolMispredicted()) {
-          LOG(WARNING) << "Mispredicted NPN protocol for "
-                       << host_and_port_.ToString();
-          net_error = ERR_SSL_SNAP_START_NPN_MISPREDICTION;
-        } else {
-          // Let's verify the certificate.
-          GotoState(STATE_VERIFY_DNSSEC);
-        }
-      }
-      // Done!
-    } else {
-      // Workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=562434 -
-      // SSL_ForceHandshake returned SECSuccess prematurely.
-      rv = SECFailure;
-      net_error = ERR_SSL_PROTOCOL_ERROR;
-      net_log_.AddEvent(NetLog::TYPE_SSL_HANDSHAKE_ERROR,
-                        make_scoped_refptr(new SSLErrorParams(net_error, 0)));
-    }
-  } else {
-    PRErrorCode prerr = PR_GetError();
-    net_error = MapNSSHandshakeError(prerr);
-
-    // If not done, stay in this state
-    if (net_error == ERR_IO_PENDING) {
-      GotoState(STATE_HANDSHAKE);
-    } else {
-      LOG(ERROR) << "handshake failed; NSS error code " << prerr
-                 << ", net_error " << net_error;
-      net_log_.AddEvent(
-          NetLog::TYPE_SSL_HANDSHAKE_ERROR,
-          make_scoped_refptr(new SSLErrorParams(net_error, prerr)));
-    }
-  }
-
-  LeaveFunction("");
-  return net_error;
-}
-
-// DNSValidationResult enumerates the possible outcomes from processing a
-// set of DNS records.
-enum DNSValidationResult {
-  DNSVR_SUCCESS,   // the cert is immediately acceptable.
-  DNSVR_FAILURE,   // the cert is unconditionally rejected.
-  DNSVR_CONTINUE,  // perform CA validation as usual.
-};
-
-// VerifyTXTRecords processes the RRDATA for a number of DNS TXT records and
-// checks them against the given certificate.
-//   dnssec: if true then the TXT records are DNSSEC validated. In this case,
-//       DNSVR_SUCCESS may be returned.
-//    server_cert_nss: the certificate to validate
-//    rrdatas: the TXT records for the current domain.
-static DNSValidationResult VerifyTXTRecords(
-    bool dnssec,
-    CERTCertificate* server_cert_nss,
-    const std::vector<base::StringPiece>& rrdatas) {
-  bool found_well_formed_record = false;
-  bool matched_record = false;
-
-  for (std::vector<base::StringPiece>::const_iterator
-       i = rrdatas.begin(); i != rrdatas.end(); ++i) {
-    std::map<std::string, std::string> m(
-        DNSSECChainVerifier::ParseTLSTXTRecord(*i));
-    if (m.empty())
-      continue;
-
-    std::map<std::string, std::string>::const_iterator j;
-    j = m.find("v");
-    if (j == m.end() || j->second != "tls1")
-      continue;
-
-    j = m.find("ha");
-
-    HASH_HashType hash_algorithm;
-    unsigned hash_length;
-    if (j == m.end() || j->second == "sha1") {
-      hash_algorithm = HASH_AlgSHA1;
-      hash_length = SHA1_LENGTH;
-    } else if (j->second == "sha256") {
-      hash_algorithm = HASH_AlgSHA256;
-      hash_length = SHA256_LENGTH;
-    } else {
-      continue;
-    }
-
-    j = m.find("h");
-    if (j == m.end())
-      continue;
-
-    std::vector<uint8> given_hash;
-    if (!base::HexStringToBytes(j->second, &given_hash))
-      continue;
-
-    if (given_hash.size() != hash_length)
-      continue;
-
-    uint8 calculated_hash[SHA256_LENGTH];  // SHA256 is the largest.
-    SECStatus rv;
-
-    j = m.find("hr");
-    if (j == m.end() || j->second == "pubkey") {
-      rv = HASH_HashBuf(hash_algorithm, calculated_hash,
-                        server_cert_nss->derPublicKey.data,
-                        server_cert_nss->derPublicKey.len);
-    } else if (j->second == "cert") {
-      rv = HASH_HashBuf(hash_algorithm, calculated_hash,
-                        server_cert_nss->derCert.data,
-                        server_cert_nss->derCert.len);
-    } else {
-      continue;
-    }
-
-    if (rv != SECSuccess)
-      NOTREACHED();
-
-    found_well_formed_record = true;
-
-    if (memcmp(calculated_hash, &given_hash[0], hash_length) == 0) {
-      matched_record = true;
-      if (dnssec)
-        return DNSVR_SUCCESS;
-    }
-  }
-
-  if (found_well_formed_record && !matched_record)
-    return DNSVR_FAILURE;
-
-  return DNSVR_CONTINUE;
-}
-
-
-// CheckDNSSECChain tries to validate a DNSSEC chain embedded in
-// |server_cert_nss_|. It returns true iff a chain is found that proves the
-// value of a TXT record that contains a valid public key fingerprint.
-static DNSValidationResult CheckDNSSECChain(
-    const std::string& hostname,
-    CERTCertificate* server_cert_nss) {
-  if (!server_cert_nss)
-    return DNSVR_CONTINUE;
-
-  // CERT_FindCertExtensionByOID isn't exported so we have to install an OID,
-  // get a tag for it and find the extension by using that tag.
-  static SECOidTag dnssec_chain_tag;
-  static bool dnssec_chain_tag_valid;
-  if (!dnssec_chain_tag_valid) {
-    // It's harmless if multiple threads enter this block concurrently.
-    static const uint8 kDNSSECChainOID[] =
-        // 1.3.6.1.4.1.11129.2.1.4
-        // (iso.org.dod.internet.private.enterprises.google.googleSecurity.
-        //  certificateExtensions.dnssecEmbeddedChain)
-        {0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x01, 0x04};
-    SECOidData oid_data;
-    memset(&oid_data, 0, sizeof(oid_data));
-    oid_data.oid.data = const_cast<uint8*>(kDNSSECChainOID);
-    oid_data.oid.len = sizeof(kDNSSECChainOID);
-    oid_data.desc = "DNSSEC chain";
-    oid_data.supportedExtension = SUPPORTED_CERT_EXTENSION;
-    dnssec_chain_tag = SECOID_AddEntry(&oid_data);
-    DCHECK_NE(SEC_OID_UNKNOWN, dnssec_chain_tag);
-    dnssec_chain_tag_valid = true;
-  }
-
-  SECItem dnssec_embedded_chain;
-  SECStatus rv = CERT_FindCertExtension(server_cert_nss,
-      dnssec_chain_tag, &dnssec_embedded_chain);
-  if (rv != SECSuccess)
-    return DNSVR_CONTINUE;
-
-  base::StringPiece chain(
-      reinterpret_cast<char*>(dnssec_embedded_chain.data),
-      dnssec_embedded_chain.len);
-  std::string dns_hostname;
-  if (!DNSDomainFromDot(hostname, &dns_hostname))
-    return DNSVR_CONTINUE;
-  DNSSECChainVerifier verifier(dns_hostname, chain);
-  DNSSECChainVerifier::Error err = verifier.Verify();
-  if (err != DNSSECChainVerifier::OK) {
-    LOG(ERROR) << "DNSSEC chain verification failed: " << err;
-    return DNSVR_CONTINUE;
-  }
-
-  if (verifier.rrtype() != kDNS_TXT)
-    return DNSVR_CONTINUE;
-
-  DNSValidationResult r = VerifyTXTRecords(
-      true /* DNSSEC verified */, server_cert_nss, verifier.rrdatas());
-  SECITEM_FreeItem(&dnssec_embedded_chain, PR_FALSE);
-  return r;
-}
-
-int SSLClientSocketNSS::DoVerifyDNSSEC(int result) {
-  if (ssl_config_.dns_cert_provenance_checking_enabled &&
-      dns_cert_checker_) {
-    PeerCertificateChain certs(nss_fd_);
-    dns_cert_checker_->DoAsyncVerification(
-        host_and_port_.host(), certs.AsStringPieceVector());
-  }
-
-  if (ssl_config_.dnssec_enabled) {
-    DNSValidationResult r = CheckDNSSECChain(host_and_port_.host(),
-                                             server_cert_nss_);
-    if (r == DNSVR_SUCCESS) {
-      local_server_cert_verify_result_.cert_status |= CERT_STATUS_IS_DNSSEC;
-      server_cert_verify_result_ = &local_server_cert_verify_result_;
-      GotoState(STATE_VERIFY_CERT_COMPLETE);
-      return OK;
-    }
-  }
-
-  if (dnssec_provider_ == NULL) {
-    GotoState(STATE_VERIFY_CERT);
-    return OK;
-  }
-
-  GotoState(STATE_VERIFY_DNSSEC_COMPLETE);
-  RRResponse* response;
-  dnssec_wait_start_time_ = base::Time::Now();
-  return dnssec_provider_->GetDNSSECRecords(&response, &handshake_io_callback_);
-}
-
-int SSLClientSocketNSS::DoVerifyDNSSECComplete(int result) {
-  RRResponse* response;
-  int err = dnssec_provider_->GetDNSSECRecords(&response, NULL);
-  DCHECK_EQ(err, OK);
-
-  const base::TimeDelta elapsed = base::Time::Now() - dnssec_wait_start_time_;
-  HISTOGRAM_TIMES("Net.DNSSECWaitTime", elapsed);
-
-  GotoState(STATE_VERIFY_CERT);
-  if (!response || response->rrdatas.empty())
-    return OK;
-
-  std::vector<base::StringPiece> records;
-  records.resize(response->rrdatas.size());
-  for (unsigned i = 0; i < response->rrdatas.size(); i++)
-    records[i] = base::StringPiece(response->rrdatas[i]);
-  DNSValidationResult r =
-      VerifyTXTRecords(response->dnssec, server_cert_nss_, records);
-
-  if (!ssl_config_.dnssec_enabled) {
-    // If DNSSEC is not enabled we don't take any action based on the result,
-    // except to record the latency, above.
-    return OK;
-  }
-
-  switch (r) {
-    case DNSVR_FAILURE:
-      GotoState(STATE_VERIFY_CERT_COMPLETE);
-      local_server_cert_verify_result_.cert_status |= CERT_STATUS_NOT_IN_DNS;
-      server_cert_verify_result_ = &local_server_cert_verify_result_;
-      return ERR_CERT_NOT_IN_DNS;
-    case DNSVR_CONTINUE:
-      GotoState(STATE_VERIFY_CERT);
-      break;
-    case DNSVR_SUCCESS:
-      local_server_cert_verify_result_.cert_status |= CERT_STATUS_IS_DNSSEC;
-      server_cert_verify_result_ = &local_server_cert_verify_result_;
-      GotoState(STATE_VERIFY_CERT_COMPLETE);
-      break;
-    default:
-      NOTREACHED();
-      GotoState(STATE_VERIFY_CERT);
-  }
-
-  return OK;
-}
-
-int SSLClientSocketNSS::DoVerifyCert(int result) {
-  DCHECK(server_cert_);
-
-  GotoState(STATE_VERIFY_CERT_COMPLETE);
-  start_cert_verification_time_ = base::TimeTicks::Now();
-
-  if (ssl_host_info_.get() && !ssl_host_info_->state().certs.empty() &&
-      predicted_cert_chain_correct_) {
-    // If the SSLHostInfo had a prediction for the certificate chain of this
-    // server then it will have optimistically started a verification of that
-    // chain. So, if the prediction was correct, we should wait for that
-    // verification to finish rather than start our own.
-    net_log_.AddEvent(NetLog::TYPE_SSL_VERIFICATION_MERGED, NULL);
-    UMA_HISTOGRAM_ENUMERATION("Net.SSLVerificationMerged", 1 /* true */, 2);
-    base::TimeTicks end_time = ssl_host_info_->verification_end_time();
-    if (end_time.is_null())
-      end_time = base::TimeTicks::Now();
-    UMA_HISTOGRAM_TIMES("Net.SSLVerificationMergedMsSaved",
-                        end_time - ssl_host_info_->verification_start_time());
-    server_cert_verify_result_ = &ssl_host_info_->cert_verify_result();
-    return ssl_host_info_->WaitForCertVerification(&handshake_io_callback_);
-  } else {
-    UMA_HISTOGRAM_ENUMERATION("Net.SSLVerificationMerged", 0 /* false */, 2);
-  }
-
-  int flags = 0;
-  if (ssl_config_.rev_checking_enabled)
-    flags |= X509Certificate::VERIFY_REV_CHECKING_ENABLED;
-  if (ssl_config_.verify_ev_cert)
-    flags |= X509Certificate::VERIFY_EV_CERT;
-  verifier_.reset(new SingleRequestCertVerifier(cert_verifier_));
-  server_cert_verify_result_ = &local_server_cert_verify_result_;
-  return verifier_->Verify(server_cert_, host_and_port_.host(), flags,
-                           &local_server_cert_verify_result_,
-                           &handshake_io_callback_);
-}
-
-// Derived from AuthCertificateCallback() in
-// mozilla/source/security/manager/ssl/src/nsNSSCallbacks.cpp.
-int SSLClientSocketNSS::DoVerifyCertComplete(int result) {
-  verifier_.reset();
-
-  if (!start_cert_verification_time_.is_null()) {
-    base::TimeDelta verify_time =
-        base::TimeTicks::Now() - start_cert_verification_time_;
-    if (result == OK)
-        UMA_HISTOGRAM_TIMES("Net.SSLCertVerificationTime", verify_time);
-    else
-        UMA_HISTOGRAM_TIMES("Net.SSLCertVerificationTimeError", verify_time);
-  }
-
-  if (ssl_host_info_.get())
-    ssl_host_info_->set_cert_verification_finished_time();
-
-  // We used to remember the intermediate CA certs in the NSS database
-  // persistently.  However, NSS opens a connection to the SQLite database
-  // during NSS initialization and doesn't close the connection until NSS
-  // shuts down.  If the file system where the database resides is gone,
-  // the database connection goes bad.  What's worse, the connection won't
-  // recover when the file system comes back.  Until this NSS or SQLite bug
-  // is fixed, we need to  avoid using the NSS database for non-essential
-  // purposes.  See https://bugzilla.mozilla.org/show_bug.cgi?id=508081 and
-  // http://crbug.com/15630 for more info.
-
-  // If we have been explicitly told to accept this certificate, override the
-  // result of verifier_.Verify.
-  // Eventually, we should cache the cert verification results so that we don't
-  // need to call verifier_.Verify repeatedly.  But for now we need to do this.
-  // Alternatively, we could use the cert's status that we stored along with
-  // the cert in the allowed_bad_certs vector.
-  if (IsCertificateError(result) &&
-      ssl_config_.IsAllowedBadCert(server_cert_)) {
-    VLOG(1) << "accepting bad SSL certificate, as user told us to";
-    result = OK;
-  }
-
-  if (result == OK)
-    LogConnectionTypeMetrics();
-
-  completed_handshake_ = true;
-
-  // If we merged a Write call into the handshake we need to make the
-  // callback now.
-  if (user_write_callback_) {
-    corked_ = false;
-    if (result != OK) {
-      DoWriteCallback(result);
-    } else {
-      SSLSnapStartResult snap_start_type;
-      SECStatus rv = SSL_GetSnapStartResult(nss_fd_, &snap_start_type);
-      DCHECK_EQ(rv, SECSuccess);
-      DCHECK_NE(snap_start_type, SSL_SNAP_START_NONE);
-      if (snap_start_type == SSL_SNAP_START_RECOVERY ||
-          snap_start_type == SSL_SNAP_START_RESUME_RECOVERY) {
-        // If we mispredicted the server's handshake then Snap Start will have
-        // triggered a recovery mode. The misprediction could have been caused
-        // by the server having a different certificate so the application data
-        // wasn't resent. Now that we have verified the certificate, we need to
-        // resend the application data.
-        int bytes_written = DoPayloadWrite();
-        if (bytes_written != ERR_IO_PENDING)
-          DoWriteCallback(bytes_written);
-      } else {
-        DoWriteCallback(user_write_buf_len_);
-      }
-    }
-  }
-
-  if (user_read_callback_) {
-    int rv = DoReadLoop(OK);
-    if (rv != ERR_IO_PENDING)
-      DoReadCallback(rv);
-  }
-
-  // Exit DoHandshakeLoop and return the result to the caller to Connect.
-  DCHECK(next_handshake_state_ == STATE_NONE);
-  return result;
-}
-
-int SSLClientSocketNSS::DoPayloadRead() {
-  EnterFunction(user_read_buf_len_);
-  DCHECK(user_read_buf_);
-  DCHECK_GT(user_read_buf_len_, 0);
-  int rv = PR_Read(nss_fd_, user_read_buf_->data(), user_read_buf_len_);
-  if (client_auth_cert_needed_) {
-    // We don't need to invalidate the non-client-authenticated SSL session
-    // because the server will renegotiate anyway.
-    LeaveFunction("");
-    rv = ERR_SSL_CLIENT_AUTH_CERT_NEEDED;
-    net_log_.AddEvent(NetLog::TYPE_SSL_READ_ERROR,
-                      make_scoped_refptr(new SSLErrorParams(rv, 0)));
-    return rv;
-  }
-  if (rv >= 0) {
-    LogData(user_read_buf_->data(), rv);
-    LeaveFunction("");
-    return rv;
-  }
-  PRErrorCode prerr = PR_GetError();
-  if (prerr == PR_WOULD_BLOCK_ERROR) {
-    LeaveFunction("");
-    return ERR_IO_PENDING;
-  }
-  LeaveFunction("");
-  rv = MapNSSError(prerr);
-  net_log_.AddEvent(NetLog::TYPE_SSL_READ_ERROR,
-                    make_scoped_refptr(new SSLErrorParams(rv, prerr)));
-  return rv;
-}
-
-int SSLClientSocketNSS::DoPayloadWrite() {
-  EnterFunction(user_write_buf_len_);
-  DCHECK(user_write_buf_);
-  int rv = PR_Write(nss_fd_, user_write_buf_->data(), user_write_buf_len_);
-  if (rv >= 0) {
-    LogData(user_write_buf_->data(), rv);
-    LeaveFunction("");
-    return rv;
-  }
-  PRErrorCode prerr = PR_GetError();
-  if (prerr == PR_WOULD_BLOCK_ERROR) {
-    LeaveFunction("");
-    return ERR_IO_PENDING;
-  }
-  LeaveFunction("");
-  rv = MapNSSError(prerr);
-  net_log_.AddEvent(NetLog::TYPE_SSL_WRITE_ERROR,
-                    make_scoped_refptr(new SSLErrorParams(rv, prerr)));
-  return rv;
-}
-
-void SSLClientSocketNSS::LogConnectionTypeMetrics() const {
-  UpdateConnectionTypeHistograms(CONNECTION_SSL);
-  if (server_cert_verify_result_->has_md5)
-    UpdateConnectionTypeHistograms(CONNECTION_SSL_MD5);
-  if (server_cert_verify_result_->has_md2)
-    UpdateConnectionTypeHistograms(CONNECTION_SSL_MD2);
-  if (server_cert_verify_result_->has_md4)
-    UpdateConnectionTypeHistograms(CONNECTION_SSL_MD4);
-  if (server_cert_verify_result_->has_md5_ca)
-    UpdateConnectionTypeHistograms(CONNECTION_SSL_MD5_CA);
-  if (server_cert_verify_result_->has_md2_ca)
-    UpdateConnectionTypeHistograms(CONNECTION_SSL_MD2_CA);
-  int ssl_version = SSLConnectionStatusToVersion(ssl_connection_status_);
-  switch (ssl_version) {
-    case SSL_CONNECTION_VERSION_SSL2:
-      UpdateConnectionTypeHistograms(CONNECTION_SSL_SSL2);
-      break;
-    case SSL_CONNECTION_VERSION_SSL3:
-      UpdateConnectionTypeHistograms(CONNECTION_SSL_SSL3);
-      break;
-    case SSL_CONNECTION_VERSION_TLS1:
-      UpdateConnectionTypeHistograms(CONNECTION_SSL_TLS1);
-      break;
-    case SSL_CONNECTION_VERSION_TLS1_1:
-      UpdateConnectionTypeHistograms(CONNECTION_SSL_TLS1_1);
-      break;
-    case SSL_CONNECTION_VERSION_TLS1_2:
-      UpdateConnectionTypeHistograms(CONNECTION_SSL_TLS1_2);
-      break;
-  };
-}
-
 }  // namespace net
diff --git a/net/socket/ssl_client_socket_nss.h b/net/socket/ssl_client_socket_nss.h
index bca4166a..f0e089c7 100644
--- a/net/socket/ssl_client_socket_nss.h
+++ b/net/socket/ssl_client_socket_nss.h
@@ -53,6 +53,9 @@
                      DnsCertProvenanceChecker* dnsrr_resolver);
   ~SSLClientSocketNSS();
 
+  // For tests
+  static void ClearSessionCache();
+
   // SSLClientSocket methods:
   virtual void GetSSLInfo(SSLInfo* ssl_info);
   virtual void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info);
@@ -77,10 +80,20 @@
   virtual bool SetReceiveBufferSize(int32 size);
   virtual bool SetSendBufferSize(int32 size);
 
-  // For tests
-  static void ClearSessionCache();
-
  private:
+  enum State {
+    STATE_NONE,
+    STATE_SNAP_START_LOAD_INFO,
+    STATE_SNAP_START_WAIT_FOR_WRITE,
+    STATE_HANDSHAKE,
+    STATE_VERIFY_DNSSEC,
+    STATE_VERIFY_DNSSEC_COMPLETE,
+    STATE_VERIFY_CERT,
+    STATE_VERIFY_CERT_COMPLETE,
+  };
+
+  int Init();
+
   // Initializes NSS SSL options.  Returns a net error code.
   int InitializeSSLOptions();
 
@@ -115,7 +128,6 @@
   int DoPayloadRead();
   int DoPayloadWrite();
   void LogConnectionTypeMetrics() const;
-  int Init();
   void SaveSnapStartInfo();
   bool LoadSnapStartInfo();
   bool IsNPNProtocolMispredicted();
@@ -123,8 +135,8 @@
 
   bool DoTransportIO();
   int BufferSend(void);
-  int BufferRecv(void);
   void BufferSendComplete(int result);
+  int BufferRecv(void);
   void BufferRecvComplete(int result);
 
   // NSS calls this when checking certificates. We pass 'this' as the first
@@ -224,16 +236,6 @@
   // The time when we started waiting for DNSSEC records.
   base::Time dnssec_wait_start_time_;
 
-  enum State {
-    STATE_NONE,
-    STATE_SNAP_START_LOAD_INFO,
-    STATE_SNAP_START_WAIT_FOR_WRITE,
-    STATE_HANDSHAKE,
-    STATE_VERIFY_DNSSEC,
-    STATE_VERIFY_DNSSEC_COMPLETE,
-    STATE_VERIFY_CERT,
-    STATE_VERIFY_CERT_COMPLETE,
-  };
   State next_handshake_state_;
 
   // The NSS SSL state machine
diff --git a/net/socket/ssl_server_socket_nss.cc b/net/socket/ssl_server_socket_nss.cc
index 283ba50..61284fb 100644
--- a/net/socket/ssl_server_socket_nss.cc
+++ b/net/socket/ssl_server_socket_nss.cc
@@ -90,22 +90,6 @@
   }
 }
 
-int SSLServerSocketNSS::Init() {
-  // Initialize the NSS SSL library in a threadsafe way.  This also
-  // initializes the NSS base library.
-  EnsureNSSSSLInit();
-  if (!NSS_IsInitialized())
-    return ERR_UNEXPECTED;
-#if !defined(OS_MACOSX) && !defined(OS_WIN)
-  // We must call EnsureOCSPInit() here, on the IO thread, to get the IO loop
-  // by MessageLoopForIO::current().
-  // X509Certificate::Verify() runs on a worker thread of CertVerifier.
-  EnsureOCSPInit();
-#endif
-
-  return OK;
-}
-
 int SSLServerSocketNSS::Accept(CompletionCallback* callback) {
   net_log_.BeginEvent(NetLog::TYPE_SSL_ACCEPT, NULL);
 
@@ -183,27 +167,12 @@
   return rv;
 }
 
-// static
-// NSS calls this if an incoming certificate needs to be verified.
-// Do nothing but return SECSuccess.
-// This is called only in full handshake mode.
-// Peer certificate is retrieved in HandshakeCallback() later, which is called
-// in full handshake mode or in resumption handshake mode.
-SECStatus SSLServerSocketNSS::OwnAuthCertHandler(void* arg,
-                                                 PRFileDesc* socket,
-                                                 PRBool checksig,
-                                                 PRBool is_server) {
-  // TODO(hclam): Implement.
-  // Tell NSS to not verify the certificate.
-  return SECSuccess;
+bool SSLServerSocketNSS::SetReceiveBufferSize(int32 size) {
+  return false;
 }
 
-// static
-// NSS calls this when handshake is completed.
-// After the SSL handshake is finished we need to verify the certificate.
-void SSLServerSocketNSS::HandshakeCallback(PRFileDesc* socket,
-                                           void* arg) {
-  // TODO(hclam): Implement.
+bool SSLServerSocketNSS::SetSendBufferSize(int32 size) {
+  return false;
 }
 
 int SSLServerSocketNSS::InitializeSSLOptions() {
@@ -381,6 +350,47 @@
   return OK;
 }
 
+void SSLServerSocketNSS::OnSendComplete(int result) {
+  if (next_handshake_state_ == STATE_HANDSHAKE) {
+    // In handshake phase.
+    OnHandshakeIOComplete(result);
+    return;
+  }
+
+  if (!user_write_buf_ || !completed_handshake_)
+    return;
+
+  int rv = DoWriteLoop(result);
+  if (rv != ERR_IO_PENDING)
+    DoWriteCallback(rv);
+}
+
+void SSLServerSocketNSS::OnRecvComplete(int result) {
+  if (next_handshake_state_ == STATE_HANDSHAKE) {
+    // In handshake phase.
+    OnHandshakeIOComplete(result);
+    return;
+  }
+
+  // Network layer received some data, check if client requested to read
+  // decrypted data.
+  if (!user_read_buf_ || !completed_handshake_)
+    return;
+
+  int rv = DoReadLoop(result);
+  if (rv != ERR_IO_PENDING)
+    DoReadCallback(rv);
+}
+
+void SSLServerSocketNSS::OnHandshakeIOComplete(int result) {
+  int rv = DoHandshakeLoop(result);
+  if (rv != ERR_IO_PENDING) {
+    net_log_.EndEvent(net::NetLog::TYPE_SSL_ACCEPT, NULL);
+    if (user_accept_callback_)
+      DoAcceptCallback(rv);
+  }
+}
+
 // Return 0 for EOF,
 // > 0 for bytes transferred immediately,
 // < 0 for error (or the non-error ERR_IO_PENDING).
@@ -453,81 +463,6 @@
   OnRecvComplete(result);
 }
 
-void SSLServerSocketNSS::OnSendComplete(int result) {
-  if (next_handshake_state_ == STATE_HANDSHAKE) {
-    // In handshake phase.
-    OnHandshakeIOComplete(result);
-    return;
-  }
-
-  if (!user_write_buf_ || !completed_handshake_)
-    return;
-
-  int rv = DoWriteLoop(result);
-  if (rv != ERR_IO_PENDING)
-    DoWriteCallback(rv);
-}
-
-void SSLServerSocketNSS::OnRecvComplete(int result) {
-  if (next_handshake_state_ == STATE_HANDSHAKE) {
-    // In handshake phase.
-    OnHandshakeIOComplete(result);
-    return;
-  }
-
-  // Network layer received some data, check if client requested to read
-  // decrypted data.
-  if (!user_read_buf_ || !completed_handshake_)
-    return;
-
-  int rv = DoReadLoop(result);
-  if (rv != ERR_IO_PENDING)
-    DoReadCallback(rv);
-}
-
-void SSLServerSocketNSS::OnHandshakeIOComplete(int result) {
-  int rv = DoHandshakeLoop(result);
-  if (rv != ERR_IO_PENDING) {
-    net_log_.EndEvent(net::NetLog::TYPE_SSL_ACCEPT, NULL);
-    if (user_accept_callback_)
-      DoAcceptCallback(rv);
-  }
-}
-
-void SSLServerSocketNSS::DoAcceptCallback(int rv) {
-  DCHECK_NE(rv, ERR_IO_PENDING);
-
-  CompletionCallback* c = user_accept_callback_;
-  user_accept_callback_ = NULL;
-  c->Run(rv > OK ? OK : rv);
-}
-
-void SSLServerSocketNSS::DoReadCallback(int rv) {
-  DCHECK(rv != ERR_IO_PENDING);
-  DCHECK(user_read_callback_);
-
-  // Since Run may result in Read being called, clear |user_read_callback_|
-  // up front.
-  CompletionCallback* c = user_read_callback_;
-  user_read_callback_ = NULL;
-  user_read_buf_ = NULL;
-  user_read_buf_len_ = 0;
-  c->Run(rv);
-}
-
-void SSLServerSocketNSS::DoWriteCallback(int rv) {
-  DCHECK(rv != ERR_IO_PENDING);
-  DCHECK(user_write_callback_);
-
-  // Since Run may result in Write being called, clear |user_write_callback_|
-  // up front.
-  CompletionCallback* c = user_write_callback_;
-  user_write_callback_ = NULL;
-  user_write_buf_ = NULL;
-  user_write_buf_len_ = 0;
-  c->Run(rv);
-}
-
 // Do network I/O between the given buffer and the given socket.
 // Return true if some I/O performed, false otherwise (error or ERR_IO_PENDING)
 bool SSLServerSocketNSS::DoTransportIO() {
@@ -674,4 +609,77 @@
   return net_error;
 }
 
+void SSLServerSocketNSS::DoAcceptCallback(int rv) {
+  DCHECK_NE(rv, ERR_IO_PENDING);
+
+  CompletionCallback* c = user_accept_callback_;
+  user_accept_callback_ = NULL;
+  c->Run(rv > OK ? OK : rv);
+}
+
+void SSLServerSocketNSS::DoReadCallback(int rv) {
+  DCHECK(rv != ERR_IO_PENDING);
+  DCHECK(user_read_callback_);
+
+  // Since Run may result in Read being called, clear |user_read_callback_|
+  // up front.
+  CompletionCallback* c = user_read_callback_;
+  user_read_callback_ = NULL;
+  user_read_buf_ = NULL;
+  user_read_buf_len_ = 0;
+  c->Run(rv);
+}
+
+void SSLServerSocketNSS::DoWriteCallback(int rv) {
+  DCHECK(rv != ERR_IO_PENDING);
+  DCHECK(user_write_callback_);
+
+  // Since Run may result in Write being called, clear |user_write_callback_|
+  // up front.
+  CompletionCallback* c = user_write_callback_;
+  user_write_callback_ = NULL;
+  user_write_buf_ = NULL;
+  user_write_buf_len_ = 0;
+  c->Run(rv);
+}
+
+// static
+// NSS calls this if an incoming certificate needs to be verified.
+// Do nothing but return SECSuccess.
+// This is called only in full handshake mode.
+// Peer certificate is retrieved in HandshakeCallback() later, which is called
+// in full handshake mode or in resumption handshake mode.
+SECStatus SSLServerSocketNSS::OwnAuthCertHandler(void* arg,
+                                                 PRFileDesc* socket,
+                                                 PRBool checksig,
+                                                 PRBool is_server) {
+  // TODO(hclam): Implement.
+  // Tell NSS to not verify the certificate.
+  return SECSuccess;
+}
+
+// static
+// NSS calls this when handshake is completed.
+// After the SSL handshake is finished we need to verify the certificate.
+void SSLServerSocketNSS::HandshakeCallback(PRFileDesc* socket,
+                                           void* arg) {
+  // TODO(hclam): Implement.
+}
+
+int SSLServerSocketNSS::Init() {
+  // Initialize the NSS SSL library in a threadsafe way.  This also
+  // initializes the NSS base library.
+  EnsureNSSSSLInit();
+  if (!NSS_IsInitialized())
+    return ERR_UNEXPECTED;
+#if !defined(OS_MACOSX) && !defined(OS_WIN)
+  // We must call EnsureOCSPInit() here, on the IO thread, to get the IO loop
+  // by MessageLoopForIO::current().
+  // X509Certificate::Verify() runs on a worker thread of CertVerifier.
+  EnsureOCSPInit();
+#endif
+
+  return OK;
+}
+
 }  // namespace net
diff --git a/net/socket/ssl_server_socket_nss.h b/net/socket/ssl_server_socket_nss.h
index 3883c9b77..1289272 100644
--- a/net/socket/ssl_server_socket_nss.h
+++ b/net/socket/ssl_server_socket_nss.h
@@ -42,11 +42,14 @@
                    CompletionCallback* callback);
   virtual int Write(IOBuffer* buf, int buf_len,
                     CompletionCallback* callback);
-  virtual bool SetReceiveBufferSize(int32 size) { return false; }
-  virtual bool SetSendBufferSize(int32 size) { return false; }
+  virtual bool SetReceiveBufferSize(int32 size);
+  virtual bool SetSendBufferSize(int32 size);
 
  private:
-  virtual int Init();
+  enum State {
+    STATE_NONE,
+    STATE_HANDSHAKE,
+  };
 
   int InitializeSSLOptions();
 
@@ -59,8 +62,8 @@
   int BufferRecv();
   void BufferRecvComplete(int result);
   bool DoTransportIO();
-  int DoPayloadWrite();
   int DoPayloadRead();
+  int DoPayloadWrite();
 
   int DoHandshakeLoop(int last_io_result);
   int DoReadLoop(int result);
@@ -76,6 +79,8 @@
                                       PRBool is_server);
   static void HandshakeCallback(PRFileDesc* socket, void* arg);
 
+  virtual int Init();
+
   // Members used to send and receive buffer.
   CompletionCallbackImpl<SSLServerSocketNSS> buffer_send_callback_;
   CompletionCallbackImpl<SSLServerSocketNSS> buffer_recv_callback_;
@@ -118,10 +123,6 @@
   // Private key used by the server.
   scoped_ptr<base::RSAPrivateKey> key_;
 
-  enum State {
-    STATE_NONE,
-    STATE_HANDSHAKE,
-  };
   State next_handshake_state_;
   bool completed_handshake_;
 
diff --git a/net/test/test_server.cc b/net/test/test_server.cc
index 14da7f4e..36ebf334 100644
--- a/net/test/test_server.cc
+++ b/net/test/test_server.cc
@@ -105,25 +105,6 @@
   Stop();
 }
 
-void TestServer::Init(const FilePath& document_root) {
-  // At this point, the port that the testserver will listen on is unknown.
-  // The testserver will listen on an ephemeral port, and write the port
-  // number out over a pipe that this TestServer object will read from. Once
-  // that is complete, the host_port_pair_ will contain the actual port.
-  host_port_pair_ = HostPortPair(GetHostname(type_, https_options_), 0);
-  process_handle_ = base::kNullProcessHandle;
-
-  FilePath src_dir;
-  PathService::Get(base::DIR_SOURCE_ROOT, &src_dir);
-
-  document_root_ = src_dir.Append(document_root);
-
-  certificates_dir_ = src_dir.Append(FILE_PATH_LITERAL("net"))
-                       .Append(FILE_PATH_LITERAL("data"))
-                       .Append(FILE_PATH_LITERAL("ssl"))
-                       .Append(FILE_PATH_LITERAL("certificates"));
-}
-
 bool TestServer::Start() {
   if (type_ == TYPE_HTTPS) {
     if (!LoadTestRootCert())
@@ -276,6 +257,25 @@
   return true;
 }
 
+void TestServer::Init(const FilePath& document_root) {
+  // At this point, the port that the testserver will listen on is unknown.
+  // The testserver will listen on an ephemeral port, and write the port
+  // number out over a pipe that this TestServer object will read from. Once
+  // that is complete, the host_port_pair_ will contain the actual port.
+  host_port_pair_ = HostPortPair(GetHostname(type_, https_options_), 0);
+  process_handle_ = base::kNullProcessHandle;
+
+  FilePath src_dir;
+  PathService::Get(base::DIR_SOURCE_ROOT, &src_dir);
+
+  document_root_ = src_dir.Append(document_root);
+
+  certificates_dir_ = src_dir.Append(FILE_PATH_LITERAL("net"))
+                       .Append(FILE_PATH_LITERAL("data"))
+                       .Append(FILE_PATH_LITERAL("ssl"))
+                       .Append(FILE_PATH_LITERAL("certificates"));
+}
+
 bool TestServer::SetPythonPath() {
   FilePath third_party_dir;
   if (!PathService::Get(base::DIR_SOURCE_ROOT, &third_party_dir)) {
@@ -307,6 +307,30 @@
   return true;
 }
 
+bool TestServer::ParseServerData(const std::string& server_data) {
+  VLOG(1) << "Server data: " << server_data;
+  base::JSONReader json_reader;
+  scoped_ptr<Value> value(json_reader.JsonToValue(server_data, true, false));
+  if (!value.get() ||
+      !value->IsType(Value::TYPE_DICTIONARY)) {
+    LOG(ERROR) << "Could not parse server data: "
+               << json_reader.GetErrorMessage();
+    return false;
+  }
+  server_data_.reset(static_cast<DictionaryValue*>(value.release()));
+  int port = 0;
+  if (!server_data_->GetInteger("port", &port)) {
+    LOG(ERROR) << "Could not find port value";
+    return false;
+  }
+  if ((port <= 0) || (port > kuint16max)) {
+    LOG(ERROR) << "Invalid port value: " << port;
+    return false;
+  }
+  host_port_pair_.set_port(port);
+  return true;
+}
+
 FilePath TestServer::GetRootCertificatePath() {
   return certificates_dir_.AppendASCII("root_ca_cert.crt");
 }
@@ -365,28 +389,4 @@
   return true;
 }
 
-bool TestServer::ParseServerData(const std::string& server_data) {
-  VLOG(1) << "Server data: " << server_data;
-  base::JSONReader json_reader;
-  scoped_ptr<Value> value(json_reader.JsonToValue(server_data, true, false));
-  if (!value.get() ||
-      !value->IsType(Value::TYPE_DICTIONARY)) {
-    LOG(ERROR) << "Could not parse server data: "
-               << json_reader.GetErrorMessage();
-    return false;
-  }
-  server_data_.reset(static_cast<DictionaryValue*>(value.release()));
-  int port = 0;
-  if (!server_data_->GetInteger("port", &port)) {
-    LOG(ERROR) << "Could not find port value";
-    return false;
-  }
-  if ((port <= 0) || (port > kuint16max)) {
-    LOG(ERROR) << "Invalid port value: " << port;
-    return false;
-  }
-  host_port_pair_.set_port(port);
-  return true;
-}
-
 }  // namespace net
diff --git a/net/url_request/url_request_about_job.cc b/net/url_request/url_request_about_job.cc
index b8dab1a..f48e72ab 100644
--- a/net/url_request/url_request_about_job.cc
+++ b/net/url_request/url_request_about_job.cc
@@ -12,16 +12,16 @@
 
 namespace net {
 
+URLRequestAboutJob::URLRequestAboutJob(URLRequest* request)
+    : URLRequestJob(request) {
+}
+
 // static
 URLRequestJob* URLRequestAboutJob::Factory(URLRequest* request,
                                            const std::string& scheme) {
   return new URLRequestAboutJob(request);
 }
 
-URLRequestAboutJob::URLRequestAboutJob(URLRequest* request)
-    : URLRequestJob(request) {
-}
-
 void URLRequestAboutJob::Start() {
   // Start reading asynchronously so that all error reporting and data
   // callbacks happen as they would for network requests.
diff --git a/net/url_request/url_request_about_job.h b/net/url_request/url_request_about_job.h
index 76172087..4703830 100644
--- a/net/url_request/url_request_about_job.h
+++ b/net/url_request/url_request_about_job.h
@@ -17,13 +17,14 @@
  public:
   explicit URLRequestAboutJob(URLRequest* request);
 
+  static URLRequest::ProtocolFactory Factory;
+
+  // URLRequestJob:
   virtual void Start();
   virtual bool GetMimeType(std::string* mime_type) const;
 
-  static URLRequest::ProtocolFactory Factory;
-
  private:
-  ~URLRequestAboutJob();
+  virtual ~URLRequestAboutJob();
 
   void StartAsync();
 };
diff --git a/net/url_request/url_request_context.cc b/net/url_request/url_request_context.cc
index 8e0f3bd7..6eb075c 100644
--- a/net/url_request/url_request_context.cc
+++ b/net/url_request/url_request_context.cc
@@ -25,6 +25,10 @@
       is_main_(false) {
 }
 
+void URLRequestContext::set_cookie_store(CookieStore* cookie_store) {
+  cookie_store_ = cookie_store;
+}
+
 const std::string& URLRequestContext::GetUserAgent(const GURL& url) const {
   return EmptyString();
 }
@@ -32,8 +36,4 @@
 URLRequestContext::~URLRequestContext() {
 }
 
-void URLRequestContext::set_cookie_store(CookieStore* cookie_store) {
-  cookie_store_ = cookie_store;
-}
-
 }  // namespace net
diff --git a/net/url_request/url_request_file_dir_job.cc b/net/url_request/url_request_file_dir_job.cc
index badb6b877..1cc15be 100644
--- a/net/url_request/url_request_file_dir_job.cc
+++ b/net/url_request/url_request_file_dir_job.cc
@@ -33,20 +33,6 @@
       ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
 }
 
-URLRequestFileDirJob::~URLRequestFileDirJob() {
-  DCHECK(read_pending_ == false);
-  DCHECK(lister_ == NULL);
-}
-
-void URLRequestFileDirJob::Start() {
-  // Start reading asynchronously so that all error reporting and data
-  // callbacks happen as they would for network requests.
-  MessageLoop::current()->PostTask(
-      FROM_HERE,
-      method_factory_.NewRunnableMethod(
-          &URLRequestFileDirJob::StartAsync));
-}
-
 void URLRequestFileDirJob::StartAsync() {
   DCHECK(!lister_);
 
@@ -63,6 +49,15 @@
   NotifyHeadersComplete();
 }
 
+void URLRequestFileDirJob::Start() {
+  // Start reading asynchronously so that all error reporting and data
+  // callbacks happen as they would for network requests.
+  MessageLoop::current()->PostTask(
+      FROM_HERE,
+      method_factory_.NewRunnableMethod(
+          &URLRequestFileDirJob::StartAsync));
+}
+
 void URLRequestFileDirJob::Kill() {
   if (canceled_)
     return;
@@ -174,6 +169,11 @@
   Release();  // The Lister is finished; may delete *this*
 }
 
+URLRequestFileDirJob::~URLRequestFileDirJob() {
+  DCHECK(read_pending_ == false);
+  DCHECK(lister_ == NULL);
+}
+
 void URLRequestFileDirJob::CloseLister() {
   if (lister_) {
     lister_->Cancel();
@@ -182,25 +182,6 @@
   }
 }
 
-bool URLRequestFileDirJob::FillReadBuffer(char *buf, int buf_size,
-                                          int *bytes_read) {
-  DCHECK(bytes_read);
-
-  *bytes_read = 0;
-
-  int count = std::min(buf_size, static_cast<int>(data_.size()));
-  if (count) {
-    memcpy(buf, &data_[0], count);
-    data_.erase(0, count);
-    *bytes_read = count;
-    return true;
-  } else if (list_complete_) {
-    // EOF
-    return true;
-  }
-  return false;
-}
-
 void URLRequestFileDirJob::CompleteRead() {
   if (read_pending_) {
     int bytes_read;
@@ -221,4 +202,23 @@
   }
 }
 
+bool URLRequestFileDirJob::FillReadBuffer(char *buf, int buf_size,
+                                          int *bytes_read) {
+  DCHECK(bytes_read);
+
+  *bytes_read = 0;
+
+  int count = std::min(buf_size, static_cast<int>(data_.size()));
+  if (count) {
+    memcpy(buf, &data_[0], count);
+    data_.erase(0, count);
+    *bytes_read = count;
+    return true;
+  } else if (list_complete_) {
+    // EOF
+    return true;
+  }
+  return false;
+}
+
 }  // namespace net
diff --git a/net/url_request/url_request_file_dir_job.h b/net/url_request/url_request_file_dir_job.h
index 2b40a98..f938417 100644
--- a/net/url_request/url_request_file_dir_job.h
+++ b/net/url_request/url_request_file_dir_job.h
@@ -22,9 +22,12 @@
  public:
   URLRequestFileDirJob(URLRequest* request, const FilePath& dir_path);
 
+  bool list_complete() const { return list_complete_; }
+
+  virtual void StartAsync();
+
   // Overridden from URLRequestJob:
   virtual void Start();
-  virtual void StartAsync();
   virtual void Kill();
   virtual bool ReadRawData(IOBuffer* buf, int buf_size, int *bytes_read);
   virtual bool GetMimeType(std::string* mime_type) const;
@@ -35,12 +38,11 @@
       const DirectoryLister::DirectoryListerData& data);
   virtual void OnListDone(int error);
 
-  bool list_complete() const { return list_complete_; }
-
  private:
   virtual ~URLRequestFileDirJob();
 
   void CloseLister();
+
   // When we have data and a read has been pending, this function
   // will fill the response buffer and notify the request
   // appropriately.
diff --git a/net/url_request/url_request_file_job.cc b/net/url_request/url_request_file_job.cc
index 7a1599af..0f4c423 100644
--- a/net/url_request/url_request_file_job.cc
+++ b/net/url_request/url_request_file_job.cc
@@ -82,6 +82,17 @@
 };
 #endif
 
+URLRequestFileJob::URLRequestFileJob(URLRequest* request,
+                                     const FilePath& file_path)
+    : URLRequestJob(request),
+      file_path_(file_path),
+      ALLOW_THIS_IN_INITIALIZER_LIST(
+          io_callback_(this, &URLRequestFileJob::DidRead)),
+      is_directory_(false),
+      remaining_bytes_(0),
+      ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
+}
+
 // static
 URLRequestJob* URLRequestFileJob::Factory(URLRequest* request,
                                           const std::string& scheme) {
@@ -111,22 +122,33 @@
   return new URLRequestFileJob(request, file_path);
 }
 
-URLRequestFileJob::URLRequestFileJob(URLRequest* request,
-                                     const FilePath& file_path)
-    : URLRequestJob(request),
-      file_path_(file_path),
-      ALLOW_THIS_IN_INITIALIZER_LIST(
-          io_callback_(this, &URLRequestFileJob::DidRead)),
-      is_directory_(false),
-      remaining_bytes_(0),
-      ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
-}
+#if defined(OS_CHROMEOS)
+static const char* const kLocalAccessWhiteList[] = {
+  "/home/chronos/user/Downloads",
+  "/media",
+  "/mnt/partner_partition",
+  "/usr/share/chromeos-assets",
+  "/tmp",
+  "/var/log",
+};
 
-URLRequestFileJob::~URLRequestFileJob() {
-#if defined(OS_WIN)
-  DCHECK(!async_resolver_);
-#endif
+// static
+bool URLRequestFileJob::AccessDisabled(const FilePath& file_path) {
+  if (URLRequest::IsFileAccessAllowed()) {  // for tests.
+    return false;
+  }
+
+  for (size_t i = 0; i < arraysize(kLocalAccessWhiteList); ++i) {
+    const FilePath white_listed_path(kLocalAccessWhiteList[i]);
+    // FilePath::operator== should probably handle trailing seperators.
+    if (white_listed_path == file_path.StripTrailingSeparators() ||
+        white_listed_path.IsParent(file_path)) {
+      return false;
+    }
+  }
+  return true;
 }
+#endif
 
 void URLRequestFileJob::Start() {
 #if defined(OS_WIN)
@@ -204,6 +226,43 @@
   return false;
 }
 
+bool URLRequestFileJob::IsRedirectResponse(GURL* location,
+                                           int* http_status_code) {
+  if (is_directory_) {
+    // This happens when we discovered the file is a directory, so needs a
+    // slash at the end of the path.
+    std::string new_path = request_->url().path();
+    new_path.push_back('/');
+    GURL::Replacements replacements;
+    replacements.SetPathStr(new_path);
+
+    *location = request_->url().ReplaceComponents(replacements);
+    *http_status_code = 301;  // simulate a permanent redirect
+    return true;
+  }
+
+#if defined(OS_WIN)
+  // Follow a Windows shortcut.
+  // We just resolve .lnk file, ignore others.
+  if (!LowerCaseEqualsASCII(file_path_.Extension(), ".lnk"))
+    return false;
+
+  FilePath new_path = file_path_;
+  bool resolved;
+  resolved = file_util::ResolveShortcut(&new_path);
+
+  // If shortcut is not resolved succesfully, do not redirect.
+  if (!resolved)
+    return false;
+
+  *location = FilePathToFileURL(new_path);
+  *http_status_code = 301;
+  return true;
+#else
+  return false;
+#endif
+}
+
 bool URLRequestFileJob::GetContentEncodings(
     std::vector<Filter::FilterType>* encoding_types) {
   DCHECK(encoding_types->empty());
@@ -245,6 +304,12 @@
   }
 }
 
+URLRequestFileJob::~URLRequestFileJob() {
+#if defined(OS_WIN)
+  DCHECK(!async_resolver_);
+#endif
+}
+
 void URLRequestFileJob::DidResolve(
     bool exists, const base::PlatformFileInfo& file_info) {
 #if defined(OS_WIN)
@@ -323,69 +388,4 @@
   NotifyReadComplete(result);
 }
 
-bool URLRequestFileJob::IsRedirectResponse(GURL* location,
-                                           int* http_status_code) {
-  if (is_directory_) {
-    // This happens when we discovered the file is a directory, so needs a
-    // slash at the end of the path.
-    std::string new_path = request_->url().path();
-    new_path.push_back('/');
-    GURL::Replacements replacements;
-    replacements.SetPathStr(new_path);
-
-    *location = request_->url().ReplaceComponents(replacements);
-    *http_status_code = 301;  // simulate a permanent redirect
-    return true;
-  }
-
-#if defined(OS_WIN)
-  // Follow a Windows shortcut.
-  // We just resolve .lnk file, ignore others.
-  if (!LowerCaseEqualsASCII(file_path_.Extension(), ".lnk"))
-    return false;
-
-  FilePath new_path = file_path_;
-  bool resolved;
-  resolved = file_util::ResolveShortcut(&new_path);
-
-  // If shortcut is not resolved succesfully, do not redirect.
-  if (!resolved)
-    return false;
-
-  *location = FilePathToFileURL(new_path);
-  *http_status_code = 301;
-  return true;
-#else
-  return false;
-#endif
-}
-
-#if defined(OS_CHROMEOS)
-static const char* const kLocalAccessWhiteList[] = {
-  "/home/chronos/user/Downloads",
-  "/media",
-  "/mnt/partner_partition",
-  "/usr/share/chromeos-assets",
-  "/tmp",
-  "/var/log",
-};
-
-// static
-bool URLRequestFileJob::AccessDisabled(const FilePath& file_path) {
-  if (URLRequest::IsFileAccessAllowed()) {  // for tests.
-    return false;
-  }
-
-  for (size_t i = 0; i < arraysize(kLocalAccessWhiteList); ++i) {
-    const FilePath white_listed_path(kLocalAccessWhiteList[i]);
-    // FilePath::operator== should probably handle trailing seperators.
-    if (white_listed_path == file_path.StripTrailingSeparators() ||
-        white_listed_path.IsParent(file_path)) {
-      return false;
-    }
-  }
-  return true;
-}
-#endif
-
 }  // namespace net
diff --git a/net/url_request/url_request_file_job.h b/net/url_request/url_request_file_job.h
index 1a09b04..4dbcb0b 100644
--- a/net/url_request/url_request_file_job.h
+++ b/net/url_request/url_request_file_job.h
@@ -28,6 +28,13 @@
  public:
   URLRequestFileJob(URLRequest* request, const FilePath& file_path);
 
+  static URLRequest::ProtocolFactory Factory;
+
+#if defined(OS_CHROMEOS)
+  static bool AccessDisabled(const FilePath& file_path);
+#endif
+
+  // URLRequestJob:
   virtual void Start();
   virtual void Kill();
   virtual bool ReadRawData(IOBuffer* buf, int buf_size, int* bytes_read);
@@ -37,12 +44,6 @@
   virtual bool GetMimeType(std::string* mime_type) const;
   virtual void SetExtraRequestHeaders(const HttpRequestHeaders& headers);
 
-  static URLRequest::ProtocolFactory Factory;
-
-#if defined(OS_CHROMEOS)
-  static bool AccessDisabled(const FilePath& file_path);
-#endif
-
  protected:
   virtual ~URLRequestFileJob();
 
diff --git a/net/url_request/url_request_job_manager.cc b/net/url_request/url_request_job_manager.cc
index f311cc4..5fd7be6 100644
--- a/net/url_request/url_request_job_manager.cc
+++ b/net/url_request/url_request_job_manager.cc
@@ -39,15 +39,6 @@
   { "data", URLRequestDataJob::Factory },
 };
 
-URLRequestJobManager::URLRequestJobManager() : enable_file_access_(false) {
-#ifndef NDEBUG
-  allowed_thread_ = 0;
-  allowed_thread_initialized_ = false;
-#endif
-}
-
-URLRequestJobManager::~URLRequestJobManager() {}
-
 // static
 URLRequestJobManager* URLRequestJobManager::GetInstance() {
   return Singleton<URLRequestJobManager>::get();
@@ -215,4 +206,13 @@
   interceptors_.erase(i);
 }
 
+URLRequestJobManager::URLRequestJobManager() : enable_file_access_(false) {
+#ifndef NDEBUG
+  allowed_thread_ = 0;
+  allowed_thread_initialized_ = false;
+#endif
+}
+
+URLRequestJobManager::~URLRequestJobManager() {}
+
 }  // namespace net
diff --git a/net/url_request/url_request_job_manager.h b/net/url_request/url_request_job_manager.h
index e4efcf5a..ca9ada9e 100644
--- a/net/url_request/url_request_job_manager.h
+++ b/net/url_request/url_request_job_manager.h
@@ -76,17 +76,7 @@
   URLRequestJobManager();
   ~URLRequestJobManager();
 
-  mutable base::Lock lock_;
-  FactoryMap factories_;
-  InterceptorList interceptors_;
-  bool enable_file_access_;
-
 #ifndef NDEBUG
-  // We use this to assert that CreateJob and the registration functions all
-  // run on the same thread.
-  mutable base::PlatformThreadId allowed_thread_;
-  mutable bool allowed_thread_initialized_;
-
   // The first guy to call this function sets the allowed thread.  This way we
   // avoid needing to define that thread externally.  Since we expect all
   // callers to be on the same thread, we don't worry about threads racing to
@@ -110,8 +100,18 @@
     return true;
 #endif
   }
+
+  // We use this to assert that CreateJob and the registration functions all
+  // run on the same thread.
+  mutable base::PlatformThreadId allowed_thread_;
+  mutable bool allowed_thread_initialized_;
 #endif
 
+  mutable base::Lock lock_;
+  FactoryMap factories_;
+  InterceptorList interceptors_;
+  bool enable_file_access_;
+
   DISALLOW_COPY_AND_ASSIGN(URLRequestJobManager);
 };