Update from https://crrev.com/305340

Added a few #includes of base/compiler_specific.h for upstream cleanup.

Changed callers for cc::BeginFrameArgs and cc::RendererSettings API
changes.

Review URL: https://codereview.chromium.org/754433003
diff --git a/net/BUILD.gn b/net/BUILD.gn
index be0ac53..a9d20aa 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -406,8 +406,8 @@
       "websockets/websocket_frame_parser.h",
       "websockets/websocket_handshake_constants.cc",
       "websockets/websocket_handshake_constants.h",
-      "websockets/websocket_handshake_handler.cc",
-      "websockets/websocket_handshake_handler.h",
+      "websockets/websocket_handshake_challenge.cc",
+      "websockets/websocket_handshake_challenge.h",
       "websockets/websocket_handshake_request_info.cc",
       "websockets/websocket_handshake_request_info.h",
       "websockets/websocket_handshake_response_info.cc",
@@ -609,8 +609,12 @@
 source_set("test_support") {
   testonly = true
   sources = [
+    "base/captured_net_log_entry.cc",
+    "base/captured_net_log_entry.h",
     "base/capturing_net_log.cc",
     "base/capturing_net_log.h",
+    "base/capturing_net_log_observer.cc",
+    "base/capturing_net_log_observer.h",
     "base/load_timing_info_test_util.cc",
     "base/load_timing_info_test_util.h",
     "base/mock_file_stream.cc",
@@ -1238,8 +1242,7 @@
       "websockets/websocket_extension_parser_test.cc",
       "websockets/websocket_frame_parser_test.cc",
       "websockets/websocket_frame_test.cc",
-      "websockets/websocket_handshake_handler_spdy_test.cc",
-      "websockets/websocket_handshake_handler_test.cc",
+      "websockets/websocket_handshake_challenge_test.cc",
       "websockets/websocket_handshake_stream_create_helper_test.cc",
       "websockets/websocket_inflater_test.cc",
       "websockets/websocket_stream_test.cc",
diff --git a/net/android/java/src/org/chromium/net/DefaultAndroidKeyStore.java b/net/android/java/src/org/chromium/net/DefaultAndroidKeyStore.java
index 60f910c..2a6c2f2 100644
--- a/net/android/java/src/org/chromium/net/DefaultAndroidKeyStore.java
+++ b/net/android/java/src/org/chromium/net/DefaultAndroidKeyStore.java
@@ -123,8 +123,8 @@
             signature.update(message);
             return signature.sign();
         } catch (Exception e) {
-            Log.e(TAG, "Exception while signing message with " + javaKey.getAlgorithm() +
-                        " private key: " + e);
+            Log.e(TAG, "Exception while signing message with " + javaKey.getAlgorithm()
+                    + " private key: " + e);
             return null;
         }
     }
@@ -170,8 +170,8 @@
             // This may happen if the PrivateKey was not created by the "AndroidOpenSSL"
             // provider, which should be the default. That could happen if an OEM decided
             // to implement a different default provider. Also highly unlikely.
-            Log.e(TAG, "Private key is not an OpenSSLRSAPrivateKey instance, its class name is:" +
-                       javaKey.getClass().getCanonicalName());
+            Log.e(TAG, "Private key is not an OpenSSLRSAPrivateKey instance, its class name is:"
+                    + javaKey.getClass().getCanonicalName());
             return null;
         }
 
@@ -284,8 +284,8 @@
             }
             // Sanity-check the returned engine.
             if (!engineClass.isInstance(engine)) {
-                Log.e(TAG, "Engine is not an OpenSSLEngine instance, its class name is:" +
-                        engine.getClass().getCanonicalName());
+                Log.e(TAG, "Engine is not an OpenSSLEngine instance, its class name is:"
+                        + engine.getClass().getCanonicalName());
                 return null;
             }
             return engine;
diff --git a/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java b/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java
index 1e72da9..9db46e2 100644
--- a/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java
+++ b/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java
@@ -161,8 +161,8 @@
 
     public int getCurrentConnectionType() {
         // Track exactly what type of connection we have.
-        if (!mConnectivityManagerDelegate.activeNetworkExists() ||
-                !mConnectivityManagerDelegate.isConnected()) {
+        if (!mConnectivityManagerDelegate.activeNetworkExists()
+                || !mConnectivityManagerDelegate.isConnected()) {
             return NetworkChangeNotifier.CONNECTION_NONE;
         }
 
diff --git a/net/android/java/src/org/chromium/net/X509Util.java b/net/android/java/src/org/chromium/net/X509Util.java
index 3f6c70d..08ead31 100644
--- a/net/android/java/src/org/chromium/net/X509Util.java
+++ b/net/android/java/src/org/chromium/net/X509Util.java
@@ -372,8 +372,8 @@
 
             // If the subject and public key match, this is a system root.
             X509Certificate anchorX509 = (X509Certificate) anchor;
-            if (root.getSubjectX500Principal().equals(anchorX509.getSubjectX500Principal()) &&
-                    root.getPublicKey().equals(anchorX509.getPublicKey())) {
+            if (root.getSubjectX500Principal().equals(anchorX509.getSubjectX500Principal())
+                    && root.getPublicKey().equals(anchorX509.getPublicKey())) {
                 sSystemTrustAnchorCache.add(key);
                 return true;
             }
@@ -405,10 +405,10 @@
         if (ekuOids == null) return true;
 
         for (String ekuOid : ekuOids) {
-            if (ekuOid.equals(OID_TLS_SERVER_AUTH) ||
-                    ekuOid.equals(OID_ANY_EKU) ||
-                    ekuOid.equals(OID_SERVER_GATED_NETSCAPE) ||
-                    ekuOid.equals(OID_SERVER_GATED_MICROSOFT)) {
+            if (ekuOid.equals(OID_TLS_SERVER_AUTH)
+                    || ekuOid.equals(OID_ANY_EKU)
+                    || ekuOid.equals(OID_SERVER_GATED_NETSCAPE)
+                    || ekuOid.equals(OID_SERVER_GATED_MICROSOFT)) {
                 return true;
             }
         }
@@ -421,8 +421,8 @@
                                                                    String host)
             throws KeyStoreException, NoSuchAlgorithmException {
         if (certChain == null || certChain.length == 0 || certChain[0] == null) {
-            throw new IllegalArgumentException("Expected non-null and non-empty certificate " +
-                    "chain passed as |certChain|. |certChain|=" + Arrays.deepToString(certChain));
+            throw new IllegalArgumentException("Expected non-null and non-empty certificate "
+                    + "chain passed as |certChain|. |certChain|=" + Arrays.deepToString(certChain));
         }
 
 
@@ -475,8 +475,8 @@
                 } catch (CertificateException eTestManager) {
                     // Neither of the trust managers confirms the validity of the certificate chain,
                     // log the error message returned by the system trust manager.
-                    Log.i(TAG, "Failed to validate the certificate chain, error: " +
-                              eDefaultManager.getMessage());
+                    Log.i(TAG, "Failed to validate the certificate chain, error: "
+                            + eDefaultManager.getMessage());
                     return new AndroidCertVerifyResult(
                             CertVerifyStatusAndroid.NO_TRUSTED_ROOT);
                 }
diff --git a/net/base/captured_net_log_entry.cc b/net/base/captured_net_log_entry.cc
new file mode 100644
index 0000000..9c57271
--- /dev/null
+++ b/net/base/captured_net_log_entry.cc
@@ -0,0 +1,77 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/base/captured_net_log_entry.h"
+
+#include "base/json/json_writer.h"
+#include "base/logging.h"
+#include "base/values.h"
+
+namespace net {
+
+CapturedNetLogEntry::CapturedNetLogEntry(
+    NetLog::EventType type,
+    const base::TimeTicks& time,
+    NetLog::Source source,
+    NetLog::EventPhase phase,
+    scoped_ptr<base::DictionaryValue> params)
+    : type(type),
+      time(time),
+      source(source),
+      phase(phase),
+      params(params.Pass()) {
+  // Only entries without a NetLog should have an invalid source.
+  CHECK(source.IsValid());
+}
+
+CapturedNetLogEntry::CapturedNetLogEntry(const CapturedNetLogEntry& entry) {
+  *this = entry;
+}
+
+CapturedNetLogEntry::~CapturedNetLogEntry() {}
+
+CapturedNetLogEntry& CapturedNetLogEntry::operator=(
+    const CapturedNetLogEntry& entry) {
+  type = entry.type;
+  time = entry.time;
+  source = entry.source;
+  phase = entry.phase;
+  params.reset(entry.params ? entry.params->DeepCopy() : NULL);
+  return *this;
+}
+
+bool CapturedNetLogEntry::GetStringValue(const std::string& name,
+                                         std::string* value) const {
+  if (!params)
+    return false;
+  return params->GetString(name, value);
+}
+
+bool CapturedNetLogEntry::GetIntegerValue(const std::string& name,
+                                          int* value) const {
+  if (!params)
+    return false;
+  return params->GetInteger(name, value);
+}
+
+bool CapturedNetLogEntry::GetListValue(const std::string& name,
+                                       base::ListValue** value) const {
+  if (!params)
+    return false;
+  return params->GetList(name, value);
+}
+
+bool CapturedNetLogEntry::GetNetErrorCode(int* value) const {
+  return GetIntegerValue("net_error", value);
+}
+
+std::string CapturedNetLogEntry::GetParamsJson() const {
+  if (!params)
+    return std::string();
+  std::string json;
+  base::JSONWriter::Write(params.get(), &json);
+  return json;
+}
+
+}  // namespace net
diff --git a/net/base/captured_net_log_entry.h b/net/base/captured_net_log_entry.h
new file mode 100644
index 0000000..97245e3
--- /dev/null
+++ b/net/base/captured_net_log_entry.h
@@ -0,0 +1,69 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_BASE_CAPTURED_NET_LOG_ENTRY_H_
+#define NET_BASE_CAPTURED_NET_LOG_ENTRY_H_
+
+#include <string>
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "net/base/net_log.h"
+
+namespace base {
+class DictionaryValue;
+class ListValue;
+}
+
+namespace net {
+
+// CapturedNetLogEntry is much like NetLog::Entry, except it has its own copy of
+// all log data, so a list of entries can be gathered over the course of a test,
+// and then inspected at the end.  It is intended for testing only, and is part
+// of the net_test_support project.
+struct CapturedNetLogEntry {
+  // Ordered set of logged entries.
+  typedef std::vector<CapturedNetLogEntry> List;
+
+  CapturedNetLogEntry(NetLog::EventType type,
+                      const base::TimeTicks& time,
+                      NetLog::Source source,
+                      NetLog::EventPhase phase,
+                      scoped_ptr<base::DictionaryValue> params);
+  // Copy constructor needed to store in a std::vector because of the
+  // scoped_ptr.
+  CapturedNetLogEntry(const CapturedNetLogEntry& entry);
+
+  ~CapturedNetLogEntry();
+
+  // Equality operator needed to store in a std::vector because of the
+  // scoped_ptr.
+  CapturedNetLogEntry& operator=(const CapturedNetLogEntry& entry);
+
+  // Attempt to retrieve an value of the specified type with the given name
+  // from |params|.  Returns true on success, false on failure.  Does not
+  // modify |value| on failure.
+  bool GetStringValue(const std::string& name, std::string* value) const;
+  bool GetIntegerValue(const std::string& name, int* value) const;
+  bool GetListValue(const std::string& name, base::ListValue** value) const;
+
+  // Same as GetIntegerValue, but returns the error code associated with a
+  // log entry.
+  bool GetNetErrorCode(int* value) const;
+
+  // Returns the parameters as a JSON string, or empty string if there are no
+  // parameters.
+  std::string GetParamsJson() const;
+
+  NetLog::EventType type;
+  base::TimeTicks time;
+  NetLog::Source source;
+  NetLog::EventPhase phase;
+  scoped_ptr<base::DictionaryValue> params;
+};
+
+}  // namespace net
+
+#endif  // NET_BASE_CAPTURED_NET_LOG_ENTRY_H_
diff --git a/net/base/capturing_net_log.cc b/net/base/capturing_net_log.cc
index 3837fe6..f2e2c04 100644
--- a/net/base/capturing_net_log.cc
+++ b/net/base/capturing_net_log.cc
@@ -4,130 +4,8 @@
 
 #include "net/base/capturing_net_log.h"
 
-#include "base/json/json_writer.h"
-#include "base/logging.h"
-#include "base/values.h"
-
 namespace net {
 
-CapturingNetLog::CapturedEntry::CapturedEntry(
-    EventType type,
-    const base::TimeTicks& time,
-    Source source,
-    EventPhase phase,
-    scoped_ptr<base::DictionaryValue> params)
-    : type(type),
-      time(time),
-      source(source),
-      phase(phase),
-      params(params.Pass()) {
-}
-
-CapturingNetLog::CapturedEntry::CapturedEntry(const CapturedEntry& entry) {
-  *this = entry;
-}
-
-CapturingNetLog::CapturedEntry::~CapturedEntry() {}
-
-CapturingNetLog::CapturedEntry&
-CapturingNetLog::CapturedEntry::operator=(const CapturedEntry& entry) {
-  type = entry.type;
-  time = entry.time;
-  source = entry.source;
-  phase = entry.phase;
-  params.reset(entry.params ? entry.params->DeepCopy() : NULL);
-  return *this;
-}
-
-bool CapturingNetLog::CapturedEntry::GetStringValue(
-    const std::string& name,
-    std::string* value) const {
-  if (!params)
-    return false;
-  return params->GetString(name, value);
-}
-
-bool CapturingNetLog::CapturedEntry::GetIntegerValue(
-    const std::string& name,
-    int* value) const {
-  if (!params)
-    return false;
-  return params->GetInteger(name, value);
-}
-
-bool CapturingNetLog::CapturedEntry::GetListValue(
-    const std::string& name,
-    base::ListValue** value) const {
-  if (!params)
-    return false;
-  return params->GetList(name, value);
-}
-
-bool CapturingNetLog::CapturedEntry::GetNetErrorCode(int* value) const {
-  return GetIntegerValue("net_error", value);
-}
-
-std::string CapturingNetLog::CapturedEntry::GetParamsJson() const {
-  if (!params)
-    return std::string();
-  std::string json;
-  base::JSONWriter::Write(params.get(), &json);
-  return json;
-}
-
-CapturingNetLog::Observer::Observer() {}
-
-CapturingNetLog::Observer::~Observer() {}
-
-void CapturingNetLog::Observer::GetEntries(
-    CapturedEntryList* entry_list) const {
-  base::AutoLock lock(lock_);
-  *entry_list = captured_entries_;
-}
-
-void CapturingNetLog::Observer::GetEntriesForSource(
-    NetLog::Source source,
-    CapturedEntryList* entry_list) const {
-  base::AutoLock lock(lock_);
-  entry_list->clear();
-  for (CapturedEntryList::const_iterator entry = captured_entries_.begin();
-       entry != captured_entries_.end(); ++entry) {
-    if (entry->source.id == source.id)
-      entry_list->push_back(*entry);
-  }
-}
-
-size_t CapturingNetLog::Observer::GetSize() const {
-  base::AutoLock lock(lock_);
-  return captured_entries_.size();
-}
-
-void CapturingNetLog::Observer::Clear() {
-  base::AutoLock lock(lock_);
-  captured_entries_.clear();
-}
-
-void CapturingNetLog::Observer::OnAddEntry(const net::NetLog::Entry& entry) {
-  // Only BoundNetLogs without a NetLog should have an invalid source.
-  CHECK(entry.source().IsValid());
-
-  // Using Dictionaries instead of Values makes checking values a little
-  // simpler.
-  base::DictionaryValue* param_dict = NULL;
-  base::Value* param_value = entry.ParametersToValue();
-  if (param_value && !param_value->GetAsDictionary(&param_dict))
-    delete param_value;
-
-  // Only need to acquire the lock when accessing class variables.
-  base::AutoLock lock(lock_);
-  captured_entries_.push_back(
-      CapturedEntry(entry.type(),
-                    base::TimeTicks::Now(),
-                    entry.source(),
-                    entry.phase(),
-                    scoped_ptr<base::DictionaryValue>(param_dict)));
-}
-
 CapturingNetLog::CapturingNetLog() {
   AddThreadSafeObserver(&capturing_net_log_observer_, LOG_ALL_BUT_BYTES);
 }
diff --git a/net/base/capturing_net_log.h b/net/base/capturing_net_log.h
index 5977533..452c9a0 100644
--- a/net/base/capturing_net_log.h
+++ b/net/base/capturing_net_log.h
@@ -8,68 +8,22 @@
 #include <string>
 #include <vector>
 
-#include "base/atomicops.h"
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/synchronization/lock.h"
-#include "base/time/time.h"
+#include "net/base/captured_net_log_entry.h"
+#include "net/base/capturing_net_log_observer.h"
 #include "net/base/net_log.h"
 
-namespace base {
-class DictionaryValue;
-class ListValue;
-}
-
 namespace net {
 
-// CapturingNetLog is a NetLog which instantiates Observer that saves messages
-// to a bounded buffer.  It is intended for testing only, and is part of the
-// net_test_support project. This is provided for convinience and compatilbility
-// with the old unittests.
+// CapturingNetLog is convenience class which combines a NetLog and a
+// CapturingNetLogObserver.  It is intended for testing only, and is part of the
+// net_test_support project.
 class CapturingNetLog : public NetLog {
  public:
-  struct CapturedEntry {
-    CapturedEntry(EventType type,
-                  const base::TimeTicks& time,
-                  Source source,
-                  EventPhase phase,
-                  scoped_ptr<base::DictionaryValue> params);
-    // Copy constructor needed to store in a std::vector because of the
-    // scoped_ptr.
-    CapturedEntry(const CapturedEntry& entry);
-
-    ~CapturedEntry();
-
-    // Equality operator needed to store in a std::vector because of the
-    // scoped_ptr.
-    CapturedEntry& operator=(const CapturedEntry& entry);
-
-    // Attempt to retrieve an value of the specified type with the given name
-    // from |params|.  Returns true on success, false on failure.  Does not
-    // modify |value| on failure.
-    bool GetStringValue(const std::string& name, std::string* value) const;
-    bool GetIntegerValue(const std::string& name, int* value) const;
-    bool GetListValue(const std::string& name, base::ListValue** value) const;
-
-    // Same as GetIntegerValue, but returns the error code associated with a
-    // log entry.
-    bool GetNetErrorCode(int* value) const;
-
-    // Returns the parameters as a JSON string, or empty string if there are no
-    // parameters.
-    std::string GetParamsJson() const;
-
-    EventType type;
-    base::TimeTicks time;
-    Source source;
-    EventPhase phase;
-    scoped_ptr<base::DictionaryValue> params;
-  };
-
-  // Ordered set of entries that were logged.
-  typedef std::vector<CapturedEntry> CapturedEntryList;
+  // TODO(mmenke):  Get rid of these.
+  typedef CapturedNetLogEntry CapturedEntry;
+  typedef CapturedNetLogEntry::List CapturedEntryList;
 
   CapturingNetLog();
   ~CapturingNetLog() override;
@@ -83,39 +37,7 @@
   void Clear();
 
  private:
-  // Observer is an implementation of NetLog::ThreadSafeObserver
-  // that saves messages to a bounded buffer. It is intended for testing only,
-  // and is part of the net_test_support project.
-  class Observer : public NetLog::ThreadSafeObserver {
-   public:
-    Observer();
-    ~Observer() override;
-
-    // Returns the list of all entries in the log.
-    void GetEntries(CapturedEntryList* entry_list) const;
-
-    // Fills |entry_list| with all entries in the log from the specified Source.
-    void GetEntriesForSource(Source source,
-                             CapturedEntryList* entry_list) const;
-
-    // Returns number of entries in the log.
-    size_t GetSize() const;
-
-    void Clear();
-
-   private:
-    // ThreadSafeObserver implementation:
-    void OnAddEntry(const Entry& entry) override;
-
-    // Needs to be "mutable" so can use it in GetEntries().
-    mutable base::Lock lock_;
-
-    CapturedEntryList captured_entries_;
-
-    DISALLOW_COPY_AND_ASSIGN(Observer);
-  };
-
-  Observer capturing_net_log_observer_;
+  CapturingNetLogObserver capturing_net_log_observer_;
 
   DISALLOW_COPY_AND_ASSIGN(CapturingNetLog);
 };
@@ -123,7 +45,7 @@
 // Helper class that exposes a similar API as BoundNetLog, but uses a
 // CapturingNetLog rather than the more generic NetLog.
 //
-// CapturingBoundNetLog can easily be converted to a BoundNetLog using the
+// A CapturingBoundNetLog can easily be converted to a BoundNetLog using the
 // bound() method.
 class CapturingBoundNetLog {
  public:
diff --git a/net/base/capturing_net_log_observer.cc b/net/base/capturing_net_log_observer.cc
new file mode 100644
index 0000000..da99852
--- /dev/null
+++ b/net/base/capturing_net_log_observer.cc
@@ -0,0 +1,62 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/base/capturing_net_log_observer.h"
+
+#include "base/values.h"
+
+namespace net {
+
+CapturingNetLogObserver::CapturingNetLogObserver() {}
+
+CapturingNetLogObserver::~CapturingNetLogObserver() {}
+
+void CapturingNetLogObserver::GetEntries(
+    CapturedNetLogEntry::List* entry_list) const {
+  base::AutoLock lock(lock_);
+  *entry_list = captured_entries_;
+}
+
+void CapturingNetLogObserver::GetEntriesForSource(
+    NetLog::Source source,
+    CapturedNetLogEntry::List* entry_list) const {
+  base::AutoLock lock(lock_);
+  entry_list->clear();
+  for (CapturedNetLogEntry::List::const_iterator entry =
+           captured_entries_.begin();
+       entry != captured_entries_.end(); ++entry) {
+    if (entry->source.id == source.id)
+      entry_list->push_back(*entry);
+  }
+}
+
+size_t CapturingNetLogObserver::GetSize() const {
+  base::AutoLock lock(lock_);
+  return captured_entries_.size();
+}
+
+void CapturingNetLogObserver::Clear() {
+  base::AutoLock lock(lock_);
+  captured_entries_.clear();
+}
+
+void CapturingNetLogObserver::OnAddEntry(const net::NetLog::Entry& entry) {
+  // Using Dictionaries instead of Values makes checking values a little
+  // simpler.
+  base::DictionaryValue* param_dict = nullptr;
+  base::Value* param_value = entry.ParametersToValue();
+  if (param_value && !param_value->GetAsDictionary(&param_dict))
+    delete param_value;
+
+  // Only need to acquire the lock when accessing class variables.
+  base::AutoLock lock(lock_);
+  captured_entries_.push_back(
+      CapturedNetLogEntry(entry.type(),
+                          base::TimeTicks::Now(),
+                          entry.source(),
+                          entry.phase(),
+                          scoped_ptr<base::DictionaryValue>(param_dict)));
+}
+
+}  // namespace net
diff --git a/net/base/capturing_net_log_observer.h b/net/base/capturing_net_log_observer.h
new file mode 100644
index 0000000..267352a
--- /dev/null
+++ b/net/base/capturing_net_log_observer.h
@@ -0,0 +1,58 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_BASE_CAPTURING_NET_LOG_OBSERVER_H_
+#define NET_BASE_CAPTURING_NET_LOG_OBSERVER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/synchronization/lock.h"
+#include "net/base/captured_net_log_entry.h"
+#include "net/base/net_log.h"
+
+namespace base {
+class DictionaryValue;
+class ListValue;
+}
+
+namespace net {
+
+// CapturingNetLogObserver is an implementation of NetLog::ThreadSafeObserver
+// that saves messages to a bounded buffer. It is intended for testing only,
+// and is part of the net_test_support project.
+class CapturingNetLogObserver : public NetLog::ThreadSafeObserver {
+ public:
+  CapturingNetLogObserver();
+  ~CapturingNetLogObserver() override;
+
+  // Returns the list of all entries in the log.
+  void GetEntries(CapturedNetLogEntry::List* entry_list) const;
+
+  // Fills |entry_list| with all entries in the log from the specified Source.
+  void GetEntriesForSource(NetLog::Source source,
+                           CapturedNetLogEntry::List* entry_list) const;
+
+  // Returns number of entries in the log.
+  size_t GetSize() const;
+
+  void Clear();
+
+ private:
+  // ThreadSafeObserver implementation:
+  void OnAddEntry(const NetLog::Entry& entry) override;
+
+  // Needs to be "mutable" so can use it in GetEntries().
+  mutable base::Lock lock_;
+
+  CapturedNetLogEntry::List captured_entries_;
+
+  DISALLOW_COPY_AND_ASSIGN(CapturingNetLogObserver);
+};
+
+}  // namespace net
+
+#endif  // NET_BASE_CAPTURING_NET_LOG_OBSERVER_H_
diff --git a/net/base/file_stream_context_win.cc b/net/base/file_stream_context_win.cc
index 3b942d3..369dfc1 100644
--- a/net/base/file_stream_context_win.cc
+++ b/net/base/file_stream_context_win.cc
@@ -68,14 +68,13 @@
   if (!ReadFile(file_.GetPlatformFile(), buf->data(), buf_len,
                 &bytes_read, &io_context_.overlapped)) {
     IOResult error = IOResult::FromOSError(GetLastError());
-    if (error.os_error == ERROR_IO_PENDING) {
-      IOCompletionIsPending(callback, buf);
-    } else if (error.os_error == ERROR_HANDLE_EOF) {
+    if (error.os_error == ERROR_HANDLE_EOF)
       return 0;  // Report EOF by returning 0 bytes read.
-    } else {
+    if (error.os_error == ERROR_IO_PENDING)
+      IOCompletionIsPending(callback, buf);
+    else
       LOG(WARNING) << "ReadFile failed: " << error.os_error;
-    }
-    return error.result;
+    return static_cast<int>(error.result);
   }
 
   IOCompletionIsPending(callback, buf);
@@ -89,12 +88,11 @@
   if (!WriteFile(file_.GetPlatformFile(), buf->data(), buf_len,
                  &bytes_written, &io_context_.overlapped)) {
     IOResult error = IOResult::FromOSError(GetLastError());
-    if (error.os_error == ERROR_IO_PENDING) {
+    if (error.os_error == ERROR_IO_PENDING)
       IOCompletionIsPending(callback, buf);
-    } else {
+    else
       LOG(WARNING) << "WriteFile failed: " << error.os_error;
-    }
-    return error.result;
+    return static_cast<int>(error.result);
   }
 
   IOCompletionIsPending(callback, buf);
@@ -149,7 +147,7 @@
     result = 0;
   } else if (error) {
     IOResult error_result = IOResult::FromOSError(error);
-    result = error_result.result;
+    result = static_cast<int>(error_result.result);
   } else {
     result = bytes_read;
     IncrementOffset(&io_context_.overlapped, bytes_read);
diff --git a/net/base/host_mapping_rules.cc b/net/base/host_mapping_rules.cc
index f91f3fd..01b98b7 100644
--- a/net/base/host_mapping_rules.cc
+++ b/net/base/host_mapping_rules.cc
@@ -58,7 +58,7 @@
 
     host_port->set_host(rule.replacement_hostname);
     if (rule.replacement_port != -1)
-      host_port->set_port(rule.replacement_port);
+      host_port->set_port(static_cast<uint16>(rule.replacement_port));
     return true;
   }
 
diff --git a/net/base/host_port_pair.cc b/net/base/host_port_pair.cc
index 18cf9f5..1570bbb 100644
--- a/net/base/host_port_pair.cc
+++ b/net/base/host_port_pair.cc
@@ -21,7 +21,8 @@
 
 // static
 HostPortPair HostPortPair::FromURL(const GURL& url) {
-  return HostPortPair(url.HostNoBrackets(), url.EffectiveIntPort());
+  return HostPortPair(url.HostNoBrackets(),
+                      static_cast<uint16>(url.EffectiveIntPort()));
 }
 
 // static
@@ -41,7 +42,7 @@
     return HostPortPair();
   HostPortPair host_port_pair;
   host_port_pair.set_host(key_port[0]);
-  host_port_pair.set_port(port);
+  host_port_pair.set_port(static_cast<uint16>(port));
   return host_port_pair;
 }
 
diff --git a/net/base/ip_endpoint.cc b/net/base/ip_endpoint.cc
index a0d378e..65c5d50 100644
--- a/net/base/ip_endpoint.cc
+++ b/net/base/ip_endpoint.cc
@@ -25,7 +25,7 @@
 
 IPEndPoint::~IPEndPoint() {}
 
-IPEndPoint::IPEndPoint(const IPAddressNumber& address, int port)
+IPEndPoint::IPEndPoint(const IPAddressNumber& address, uint16 port)
     : address_(address),
       port_(port) {}
 
diff --git a/net/base/ip_endpoint.h b/net/base/ip_endpoint.h
index 5e5d9c1..c2639b1 100644
--- a/net/base/ip_endpoint.h
+++ b/net/base/ip_endpoint.h
@@ -24,11 +24,11 @@
  public:
   IPEndPoint();
   ~IPEndPoint();
-  IPEndPoint(const IPAddressNumber& address, int port);
+  IPEndPoint(const IPAddressNumber& address, uint16 port);
   IPEndPoint(const IPEndPoint& endpoint);
 
   const IPAddressNumber& address() const { return address_; }
-  int port() const { return port_; }
+  uint16 port() const { return port_; }
 
   // Returns AddressFamily of the address.
   AddressFamily GetFamily() const;
@@ -66,7 +66,7 @@
 
  private:
   IPAddressNumber address_;
-  int port_;
+  uint16 port_;
 };
 
 }  // namespace net
diff --git a/net/base/ip_endpoint_unittest.cc b/net/base/ip_endpoint_unittest.cc
index 5d70911..17b325c 100644
--- a/net/base/ip_endpoint_unittest.cc
+++ b/net/base/ip_endpoint_unittest.cc
@@ -29,7 +29,7 @@
   { "::1", "[::1]", true },
   { "2001:db8:0::42", "[2001:db8::42]", true },
 };
-int test_count = arraysize(tests);
+uint16 test_count = static_cast<uint16>(arraysize(tests));
 
 class IPEndPointTest : public PlatformTest {
  public:
@@ -46,7 +46,7 @@
   IPEndPoint endpoint;
   EXPECT_EQ(0, endpoint.port());
 
-  for (int index = 0; index < test_count; ++index) {
+  for (uint16 index = 0; index < test_count; ++index) {
     IPEndPoint endpoint(tests[index].ip_address, 80);
     EXPECT_EQ(80, endpoint.port());
     EXPECT_EQ(tests[index].ip_address, endpoint.address());
@@ -54,7 +54,7 @@
 }
 
 TEST_F(IPEndPointTest, Assignment) {
-  for (int index = 0; index < test_count; ++index) {
+  for (uint16 index = 0; index < test_count; ++index) {
     IPEndPoint src(tests[index].ip_address, index);
     IPEndPoint dest = src;
 
@@ -64,7 +64,7 @@
 }
 
 TEST_F(IPEndPointTest, Copy) {
-  for (int index = 0; index < test_count; ++index) {
+  for (uint16 index = 0; index < test_count; ++index) {
     IPEndPoint src(tests[index].ip_address, index);
     IPEndPoint dest(src);
 
@@ -74,7 +74,7 @@
 }
 
 TEST_F(IPEndPointTest, ToFromSockAddr) {
-  for (int index = 0; index < test_count; ++index) {
+  for (uint16 index = 0; index < test_count; ++index) {
     IPEndPoint ip_endpoint(tests[index].ip_address, index);
 
     // Convert to a sockaddr.
@@ -97,7 +97,7 @@
 }
 
 TEST_F(IPEndPointTest, ToSockAddrBufTooSmall) {
-  for (int index = 0; index < test_count; ++index) {
+  for (uint16 index = 0; index < test_count; ++index) {
     IPEndPoint ip_endpoint(tests[index].ip_address, index);
 
     SockaddrStorage storage;
@@ -116,7 +116,7 @@
 }
 
 TEST_F(IPEndPointTest, Equality) {
-  for (int index = 0; index < test_count; ++index) {
+  for (uint16 index = 0; index < test_count; ++index) {
     IPEndPoint src(tests[index].ip_address, index);
     IPEndPoint dest(src);
     EXPECT_TRUE(src == dest);
@@ -159,8 +159,8 @@
   IPEndPoint endpoint;
   EXPECT_EQ(0, endpoint.port());
 
-  for (int index = 0; index < test_count; ++index) {
-    int port = 100 + index;
+  for (uint16 index = 0; index < test_count; ++index) {
+    uint16 port = 100 + index;
     IPEndPoint endpoint(tests[index].ip_address, port);
     const std::string result = endpoint.ToString();
     EXPECT_EQ(tests[index].host_normalized + ":" + base::IntToString(port),
diff --git a/net/base/net_log_event_type_list.h b/net/base/net_log_event_type_list.h
index 494b762..d6e6187 100644
--- a/net/base/net_log_event_type_list.h
+++ b/net/base/net_log_event_type_list.h
@@ -1325,6 +1325,10 @@
 EVENT_TYPE(SPDY_STREAM)
 
 // A stream is attached to a pushed stream.
+//   {
+//     "stream_id":  <The stream id>,
+//     "url":        <The url of the pushed resource>,
+//   }
 EVENT_TYPE(SPDY_STREAM_ADOPTED_PUSH_STREAM)
 
 // A stream is unstalled by flow control.
diff --git a/net/base/net_log_util.cc b/net/base/net_log_util.cc
index a15e899..3b437aa 100644
--- a/net/base/net_log_util.cc
+++ b/net/base/net_log_util.cc
@@ -4,12 +4,17 @@
 
 #include "net/base/net_log_util.h"
 
+#include <algorithm>
 #include <string>
+#include <vector>
 
+#include "base/bind.h"
+#include "base/logging.h"
 #include "base/metrics/field_trial.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
+#include "base/time/time.h"
 #include "base/values.h"
 #include "net/base/address_family.h"
 #include "net/base/load_states.h"
@@ -28,6 +33,7 @@
 #include "net/proxy/proxy_service.h"
 #include "net/quic/quic_protocol.h"
 #include "net/quic/quic_utils.h"
+#include "net/url_request/url_request.h"
 #include "net/url_request/url_request_context.h"
 
 namespace net {
@@ -101,6 +107,25 @@
   return http_cache->GetCurrentBackend();
 }
 
+// Returns true if |request1| was created before |request2|.
+bool RequestCreatedBefore(const net::URLRequest* request1,
+                          const net::URLRequest* request2) {
+  if (request1->creation_time() < request2->creation_time())
+    return true;
+  if (request1->creation_time() > request2->creation_time())
+    return false;
+  // If requests were created at the same time, sort by ID.  Mostly matters for
+  // testing purposes.
+  return request1->identifier() < request2->identifier();
+}
+
+// Returns a Value representing the state of a pre-existing URLRequest when
+// net-internals was opened.
+base::Value* GetRequestStateAsValue(const net::URLRequest* request,
+                                    net::NetLog::LogLevel log_level) {
+  return request->GetStateAsValue();
+}
+
 }  // namespace
 
 scoped_ptr<base::DictionaryValue> GetNetConstants() {
@@ -298,6 +323,9 @@
 
 NET_EXPORT scoped_ptr<base::DictionaryValue> GetNetInfo(
     URLRequestContext* context, int info_sources) {
+  // May only be called on the context's thread.
+  DCHECK(context->CalledOnValidThread());
+
   scoped_ptr<base::DictionaryValue> net_info_dict(new base::DictionaryValue());
 
   // TODO(mmenke):  The code for most of these sources should probably be moved
@@ -489,4 +517,41 @@
   return net_info_dict.Pass();
 }
 
+NET_EXPORT void CreateNetLogEntriesForActiveObjects(
+    const std::set<URLRequestContext*>& contexts,
+    NetLog::ThreadSafeObserver* observer) {
+  // Not safe to call this when the observer is watching a NetLog.
+  DCHECK(!observer->net_log());
+
+  // Put together the list of all requests.
+  std::vector<const URLRequest*> requests;
+  for (const auto& context : contexts) {
+    // May only be called on the context's thread.
+    DCHECK(context->CalledOnValidThread());
+    // Contexts should all be using the same NetLog.
+    DCHECK_EQ((*contexts.begin())->net_log(), context->net_log());
+    for (const auto& request : *context->url_requests()) {
+      requests.push_back(request);
+    }
+  }
+
+  // Sort by creation time.
+  std::sort(requests.begin(), requests.end(), RequestCreatedBefore);
+
+  // Create fake events.
+  ScopedVector<NetLog::Entry> entries;
+  for (const auto& request : requests) {
+    net::NetLog::ParametersCallback callback =
+        base::Bind(&GetRequestStateAsValue, base::Unretained(request));
+
+    net::NetLog::EntryData entry_data(net::NetLog::TYPE_REQUEST_ALIVE,
+                                      request->net_log().source(),
+                                      net::NetLog::PHASE_BEGIN,
+                                      request->creation_time(),
+                                      &callback);
+    NetLog::Entry entry(&entry_data, request->net_log().GetLogLevel());
+    observer->OnAddEntry(entry);
+  }
+}
+
 }  // namespace net
diff --git a/net/base/net_log_util.h b/net/base/net_log_util.h
index d9627da..d6d6857 100644
--- a/net/base/net_log_util.h
+++ b/net/base/net_log_util.h
@@ -5,8 +5,11 @@
 #ifndef NET_BASE_NET_LOG_UTIL_H_
 #define NET_BASE_NET_LOG_UTIL_H_
 
+#include <set>
+
 #include "base/memory/scoped_ptr.h"
 #include "net/base/net_export.h"
+#include "net/base/net_log.h"
 
 namespace base {
 class DictionaryValue;
@@ -28,16 +31,38 @@
 
 // Utility methods for creating NetLog dumps.
 
-// Create a dictionary containing legend for net/ constants.
+// Create a dictionary containing a legend for net/ constants.
 NET_EXPORT scoped_ptr<base::DictionaryValue> GetNetConstants();
 
 // Retrieves a dictionary containing information about the current state of
 // |context|.  |info_sources| is a set of NetInfoSources OR'd together,
 // indicating just what information is being requested.  Each NetInfoSource adds
 // one top-level entry to the returned dictionary.
+//
+// May only be called on |context|'s thread.
 NET_EXPORT scoped_ptr<base::DictionaryValue> GetNetInfo(
     URLRequestContext* context, int info_sources);
 
+// Takes in a set of contexts and a NetLog::Observer, and passes in
+// NetLog::Entries to the observer for certain NetLog::Sources with pending
+// events.  This allows requests that were ongoing when logging was started to
+// have an initial event that has some information.  This is particularly useful
+// for hung requests.  Note that these calls are not protected by the NetLog's
+// lock, so this should generally be invoked before the observer starts watching
+// the NetLog.
+//
+// All members of |contexts| must be using the same NetLog, and live on the
+// current thread.
+//
+// Currently only creates events for URLRequests.
+//
+// The reason for not returning a list of NetLog::Entries is that entries don't
+// own most of their data, so it's simplest just to pass them in to the observer
+// directly while their data is on the stack.
+NET_EXPORT void CreateNetLogEntriesForActiveObjects(
+    const std::set<URLRequestContext*>& contexts,
+    NetLog::ThreadSafeObserver* observer);
+
 }  // namespace net
 
 #endif  // NET_BASE_NET_LOG_UTIL_H_
diff --git a/net/base/net_log_util_unittest.cc b/net/base/net_log_util_unittest.cc
index e5cc3a3..e052980 100644
--- a/net/base/net_log_util_unittest.cc
+++ b/net/base/net_log_util_unittest.cc
@@ -4,12 +4,17 @@
 
 #include "net/base/net_log_util.h"
 
+#include <set>
+
+#include "base/files/file_path.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/values.h"
+#include "net/base/capturing_net_log_observer.h"
 #include "net/base/net_errors.h"
 #include "net/base/test_completion_callback.h"
 #include "net/http/http_cache.h"
 #include "net/http/http_transaction.h"
+#include "net/test/spawned_test_server/spawned_test_server.h"
 #include "net/url_request/url_request_test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -49,6 +54,65 @@
   EXPECT_EQ(net_info_without_cache->size(), net_info_with_cache->size());
 }
 
+// Make sure CreateNetLogEntriesForActiveObjects works for requests from a
+// single URLRequestContext.
+TEST(NetLogUtil, CreateNetLogEntriesForActiveObjectsOneContext) {
+  // Using same context for each iteration makes sure deleted requests don't
+  // appear in the list, or result in crashes.
+  TestURLRequestContext context(true);
+  NetLog net_log;
+  context.set_net_log(&net_log);
+  context.Init();
+  TestDelegate delegate;
+  for (size_t num_requests = 0; num_requests < 5; ++num_requests) {
+    ScopedVector<URLRequest> requests;
+    for (size_t i = 0; i < num_requests; ++i) {
+      requests.push_back(context.CreateRequest(
+          GURL("about:life"), DEFAULT_PRIORITY, &delegate, nullptr).release());
+    }
+    std::set<URLRequestContext*> contexts;
+    contexts.insert(&context);
+    CapturingNetLogObserver capturing_observer;
+    CreateNetLogEntriesForActiveObjects(contexts, &capturing_observer);
+    CapturedNetLogEntry::List entry_list;
+    capturing_observer.GetEntries(&entry_list);
+    ASSERT_EQ(num_requests, entry_list.size());
+
+    for (size_t i = 0; i < num_requests; ++i) {
+      EXPECT_EQ(entry_list[i].source.id, requests[i]->net_log().source().id);
+    }
+  }
+}
+
+// Make sure CreateNetLogEntriesForActiveObjects works with multiple
+// URLRequestContexts.
+TEST(NetLogUtil, CreateNetLogEntriesForActiveObjectsMultipleContexts) {
+  TestDelegate delegate;
+  for (size_t num_requests = 0; num_requests < 5; ++num_requests) {
+    ScopedVector<TestURLRequestContext> contexts;
+    ScopedVector<URLRequest> requests;
+    NetLog net_log;
+    std::set<URLRequestContext*> context_set;
+    for (size_t i = 0; i < num_requests; ++i) {
+      contexts.push_back(new TestURLRequestContext(true));
+      contexts[i]->set_net_log(&net_log);
+      contexts[i]->Init();
+      context_set.insert(contexts[i]);
+      requests.push_back(contexts[i]->CreateRequest(
+          GURL("about:hats"), DEFAULT_PRIORITY, &delegate, nullptr).release());
+    }
+    CapturingNetLogObserver capturing_observer;
+    CreateNetLogEntriesForActiveObjects(context_set, &capturing_observer);
+    CapturedNetLogEntry::List entry_list;
+    capturing_observer.GetEntries(&entry_list);
+    ASSERT_EQ(num_requests, entry_list.size());
+
+    for (size_t i = 0; i < num_requests; ++i) {
+      EXPECT_EQ(entry_list[i].source.id, requests[i]->net_log().source().id);
+    }
+  }
+}
+
 }  // namespace
 
 }  // namespace net
diff --git a/net/base/net_util.cc b/net/base/net_util.cc
index 9dcf9df..3b49dff 100644
--- a/net/base/net_util.cc
+++ b/net/base/net_util.cc
@@ -306,7 +306,7 @@
       return false;
     }
   }
-  return true;
+  return IsPortValid(port);
 }
 
 bool IsPortAllowedByFtp(int port) {
@@ -573,7 +573,7 @@
     *address = reinterpret_cast<const uint8*>(&addr->btAddr);
     *address_len = kBluetoothAddressSize;
     if (port)
-      *port = addr->port;
+      *port = static_cast<uint16>(addr->port);
     return true;
   }
 #endif
@@ -1015,8 +1015,7 @@
 }
 
 NetworkInterface::NetworkInterface()
-    : type(NetworkChangeNotifier::CONNECTION_UNKNOWN),
-      network_prefix(0) {
+    : type(NetworkChangeNotifier::CONNECTION_UNKNOWN), prefix_length(0) {
 }
 
 NetworkInterface::NetworkInterface(const std::string& name,
@@ -1024,14 +1023,14 @@
                                    uint32 interface_index,
                                    NetworkChangeNotifier::ConnectionType type,
                                    const IPAddressNumber& address,
-                                   uint32 network_prefix,
+                                   uint32 prefix_length,
                                    int ip_address_attributes)
     : name(name),
       friendly_name(friendly_name),
       interface_index(interface_index),
       type(type),
       address(address),
-      network_prefix(network_prefix),
+      prefix_length(prefix_length),
       ip_address_attributes(ip_address_attributes) {
 }
 
diff --git a/net/base/net_util.h b/net/base/net_util.h
index 44b913a..9e9dbad 100644
--- a/net/base/net_util.h
+++ b/net/base/net_util.h
@@ -468,7 +468,7 @@
                    uint32 interface_index,
                    NetworkChangeNotifier::ConnectionType type,
                    const IPAddressNumber& address,
-                   uint32 network_prefix,
+                   uint32 prefix_length,
                    int ip_address_attributes);
   ~NetworkInterface();
 
@@ -477,7 +477,7 @@
   uint32 interface_index;  // Always 0 on Android.
   NetworkChangeNotifier::ConnectionType type;
   IPAddressNumber address;
-  uint32 network_prefix;
+  uint32 prefix_length;
   int ip_address_attributes;  // Combination of |IPAddressAttributes|.
 };
 
@@ -487,9 +487,6 @@
 enum HostAddressSelectionPolicy {
   INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES           = 0x0,
   EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES           = 0x1,
-  // Include temp address only when interface has both permanent and
-  // temp addresses.
-  INCLUDE_ONLY_TEMP_IPV6_ADDRESS_IF_POSSIBLE      = 0x2,
 };
 
 // Returns list of network interfaces except loopback interface. If an
diff --git a/net/base/net_util_unittest.cc b/net/base/net_util_unittest.cc
index a25903a..cb9ec1f 100644
--- a/net/base/net_util_unittest.cc
+++ b/net/base/net_util_unittest.cc
@@ -36,21 +36,22 @@
 #include <iphlpapi.h>
 #include <objbase.h>
 #include "base/win/windows_version.h"
-#include "net/base/net_util_win.h"
 #endif  // OS_WIN
 
 #if !defined(OS_MACOSX) && !defined(OS_NACL) && !defined(OS_WIN)
 #include "net/base/address_tracker_linux.h"
 #endif  // !OS_MACOSX && !OS_NACL && !OS_WIN
 
-#if !defined(OS_WIN)
+#if defined(OS_WIN)
+#include "net/base/net_util_win.h"
+#else  // OS_WIN
 #include "net/base/net_util_posix.h"
 #if defined(OS_MACOSX)
 #include "net/base/net_util_mac.h"
 #else  // OS_MACOSX
 #include "net/base/net_util_linux.h"
-#endif
-#endif  // !OS_WIN
+#endif  // OS_MACOSX
+#endif  // OS_WIN
 
 using base::ASCIIToUTF16;
 using base::WideToUTF16;
@@ -830,8 +831,8 @@
       }
     }
     EXPECT_FALSE(all_zeroes);
-    EXPECT_GT(it->network_prefix, 1u);
-    EXPECT_LE(it->network_prefix, it->address.size() * 8);
+    EXPECT_GT(it->prefix_length, 1u);
+    EXPECT_LE(it->prefix_length, it->address.size() * 8);
 
 #if defined(OS_WIN)
     // On Windows |name| is NET_LUID.
@@ -877,16 +878,32 @@
 }
 
 static const char ifname_em1[] = "em1";
+#if defined(OS_WIN)
+static const char ifname_vm[] = "VMnet";
+#else
 static const char ifname_vm[] = "vmnet";
+#endif  // OS_WIN
 
 static const unsigned char kIPv6LocalAddr[] = {
   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
+
+// The following 3 addresses need to be changed together. IPv6Addr is the IPv6
+// address. IPv6Netmask is the mask address with as many leading bits set to 1
+// as the prefix length. IPv6AddrPrefix needs to match IPv6Addr with the same
+// number of bits as the prefix length.
 static const unsigned char kIPv6Addr[] =
   {0x24, 0x01, 0xfa, 0x00, 0x00, 0x04, 0x10, 0x00, 0xbe, 0x30, 0x5b, 0xff,
    0xfe, 0xe5, 0x00, 0xc3};
+#if defined(OS_WIN)
+static const unsigned char kIPv6AddrPrefix[] =
+  {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   0x00, 0x00, 0x00, 0x00};
+#endif  // OS_WIN
+#if defined(OS_MACOSX)
 static const unsigned char kIPv6Netmask[] =
   {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00};
+#endif  // OS_MACOSX
 
 #if !defined(OS_MACOSX) && !defined(OS_WIN) && !defined(OS_NACL)
 
@@ -908,8 +925,6 @@
   IPAddressNumber ipv6_local_address(
       kIPv6LocalAddr, kIPv6LocalAddr + arraysize(kIPv6LocalAddr));
   IPAddressNumber ipv6_address(kIPv6Addr, kIPv6Addr + arraysize(kIPv6Addr));
-  IPAddressNumber ipv6_netmask(kIPv6Netmask,
-                               kIPv6Netmask + arraysize(kIPv6Netmask));
 
   NetworkInterfaceList results;
   ::base::hash_set<int> online_links;
@@ -960,7 +975,7 @@
                                         GetInterfaceNameVM));
   EXPECT_EQ(results.size(), 1ul);
   EXPECT_EQ(results[0].name, ifname_vm);
-  EXPECT_EQ(results[0].network_prefix, 1ul);
+  EXPECT_EQ(results[0].prefix_length, 1ul);
   EXPECT_EQ(results[0].address, ipv6_address);
   results.clear();
 
@@ -1002,7 +1017,7 @@
                                         GetInterfaceName));
   EXPECT_EQ(results.size(), 1ul);
   EXPECT_EQ(results[0].name, ifname_em1);
-  EXPECT_EQ(results[0].network_prefix, 1ul);
+  EXPECT_EQ(results[0].prefix_length, 1ul);
   EXPECT_EQ(results[0].address, ipv6_address);
   EXPECT_EQ(results[0].ip_address_attributes, IP_ADDRESS_ATTRIBUTE_TEMPORARY);
   results.clear();
@@ -1020,7 +1035,7 @@
                                         GetInterfaceName));
   EXPECT_EQ(results.size(), 1ul);
   EXPECT_EQ(results[0].name, ifname_em1);
-  EXPECT_EQ(results[0].network_prefix, 1ul);
+  EXPECT_EQ(results[0].prefix_length, 1ul);
   EXPECT_EQ(results[0].address, ipv6_address);
   EXPECT_EQ(results[0].ip_address_attributes, IP_ADDRESS_ATTRIBUTE_DEPRECATED);
   results.clear();
@@ -1064,7 +1079,7 @@
       &ip_attributes_getter));
   EXPECT_EQ(results.size(), 1ul);
   EXPECT_EQ(results[0].name, ifname_vm);
-  EXPECT_EQ(results[0].network_prefix, 1ul);
+  EXPECT_EQ(results[0].prefix_length, 1ul);
   EXPECT_EQ(results[0].address, ipv6_address);
   results.clear();
 
@@ -1098,7 +1113,7 @@
       &ip_attributes_getter));
   EXPECT_EQ(results.size(), 1ul);
   EXPECT_EQ(results[0].name, ifname_em1);
-  EXPECT_EQ(results[0].network_prefix, 1ul);
+  EXPECT_EQ(results[0].prefix_length, 1ul);
   EXPECT_EQ(results[0].address, ipv6_address);
   EXPECT_EQ(results[0].ip_address_attributes, IP_ADDRESS_ATTRIBUTE_TEMPORARY);
   results.clear();
@@ -1113,12 +1128,181 @@
       &ip_attributes_getter));
   EXPECT_EQ(results.size(), 1ul);
   EXPECT_EQ(results[0].name, ifname_em1);
-  EXPECT_EQ(results[0].network_prefix, 1ul);
+  EXPECT_EQ(results[0].prefix_length, 1ul);
   EXPECT_EQ(results[0].address, ipv6_address);
   EXPECT_EQ(results[0].ip_address_attributes, IP_ADDRESS_ATTRIBUTE_DEPRECATED);
   results.clear();
 #endif  // !OS_IOS
 }
+#elif defined(OS_WIN)  // !OS_MACOSX && !OS_WIN && !OS_NACL
+
+// Helper function to create a valid IP_ADAPTER_ADDRESSES with reasonable
+// default value. The output is the |adapter_address|. All the rests are input
+// to fill the |adapter_address|. |sock_addrs| are temporary storage used by
+// |adapter_address| once the function is returned.
+bool FillAdapterAddress(IP_ADAPTER_ADDRESSES* adapter_address,
+                        const char* ifname,
+                        const IPAddressNumber& ip_address,
+                        const IPAddressNumber& ip_netmask,
+                        sockaddr_storage sock_addrs[2]) {
+  adapter_address->AdapterName = const_cast<char*>(ifname);
+  adapter_address->FriendlyName = const_cast<PWCHAR>(L"interface");
+  adapter_address->IfType = IF_TYPE_ETHERNET_CSMACD;
+  adapter_address->OperStatus = IfOperStatusUp;
+  adapter_address->FirstUnicastAddress->DadState = IpDadStatePreferred;
+  adapter_address->FirstUnicastAddress->PrefixOrigin = IpPrefixOriginOther;
+  adapter_address->FirstUnicastAddress->SuffixOrigin = IpSuffixOriginOther;
+  adapter_address->FirstUnicastAddress->PreferredLifetime = 100;
+  adapter_address->FirstUnicastAddress->ValidLifetime = 1000;
+
+  socklen_t sock_len = sizeof(sockaddr_storage);
+
+  // Convert to sockaddr for next check.
+  if (!IPEndPoint(ip_address, 0)
+           .ToSockAddr(reinterpret_cast<sockaddr*>(&sock_addrs[0]),
+                       &sock_len)) {
+    return false;
+  }
+  adapter_address->FirstUnicastAddress->Address.lpSockaddr =
+      reinterpret_cast<sockaddr*>(&sock_addrs[0]);
+  adapter_address->FirstUnicastAddress->Address.iSockaddrLength = sock_len;
+  adapter_address->FirstUnicastAddress->OnLinkPrefixLength = 1;
+
+  sock_len = sizeof(sockaddr_storage);
+  if (!IPEndPoint(ip_netmask, 0)
+           .ToSockAddr(reinterpret_cast<sockaddr*>(&sock_addrs[1]),
+                       &sock_len)) {
+    return false;
+  }
+  adapter_address->FirstPrefix->Address.lpSockaddr =
+      reinterpret_cast<sockaddr*>(&sock_addrs[1]);
+  adapter_address->FirstPrefix->Address.iSockaddrLength = sock_len;
+  adapter_address->FirstPrefix->PrefixLength = 1;
+
+  DCHECK_EQ(sock_addrs[0].ss_family, sock_addrs[1].ss_family);
+  if (sock_addrs[0].ss_family == AF_INET6) {
+    adapter_address->Ipv6IfIndex = 0;
+  } else {
+    DCHECK_EQ(sock_addrs[0].ss_family, AF_INET);
+    adapter_address->IfIndex = 0;
+  }
+
+  return true;
+}
+
+TEST(NetUtilTest, GetNetworkListTrimming) {
+  IPAddressNumber ipv6_local_address(
+      kIPv6LocalAddr, kIPv6LocalAddr + arraysize(kIPv6LocalAddr));
+  IPAddressNumber ipv6_address(kIPv6Addr, kIPv6Addr + arraysize(kIPv6Addr));
+  IPAddressNumber ipv6_prefix(kIPv6AddrPrefix,
+                              kIPv6AddrPrefix + arraysize(kIPv6AddrPrefix));
+
+  NetworkInterfaceList results;
+  sockaddr_storage addresses[2];
+  IP_ADAPTER_ADDRESSES adapter_address = {0};
+  IP_ADAPTER_UNICAST_ADDRESS address = {0};
+  IP_ADAPTER_PREFIX adapter_prefix = {0};
+  adapter_address.FirstUnicastAddress = &address;
+  adapter_address.FirstPrefix = &adapter_prefix;
+
+  // Address of offline links should be ignored.
+  ASSERT_TRUE(FillAdapterAddress(
+      &adapter_address /* adapter_address */, ifname_em1 /* ifname */,
+      ipv6_address /* ip_address */, ipv6_prefix /* ip_netmask */,
+      addresses /* sock_addrs */));
+  adapter_address.OperStatus = IfOperStatusDown;
+
+  EXPECT_TRUE(net::internal::GetNetworkListImpl(
+      &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, true, &adapter_address));
+
+  EXPECT_EQ(results.size(), 0ul);
+
+  // Address on loopback interface should be trimmed out.
+  ASSERT_TRUE(FillAdapterAddress(
+      &adapter_address /* adapter_address */, ifname_em1 /* ifname */,
+      ipv6_local_address /* ip_address */, ipv6_prefix /* ip_netmask */,
+      addresses /* sock_addrs */));
+  adapter_address.IfType = IF_TYPE_SOFTWARE_LOOPBACK;
+
+  EXPECT_TRUE(net::internal::GetNetworkListImpl(
+      &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, true, &adapter_address));
+  EXPECT_EQ(results.size(), 0ul);
+
+  // vmware address should return by default.
+  ASSERT_TRUE(FillAdapterAddress(
+      &adapter_address /* adapter_address */, ifname_vm /* ifname */,
+      ipv6_address /* ip_address */, ipv6_prefix /* ip_netmask */,
+      addresses /* sock_addrs */));
+  EXPECT_TRUE(net::internal::GetNetworkListImpl(
+      &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, true, &adapter_address));
+  EXPECT_EQ(results.size(), 1ul);
+  EXPECT_EQ(results[0].name, ifname_vm);
+  EXPECT_EQ(results[0].prefix_length, 1ul);
+  EXPECT_EQ(results[0].address, ipv6_address);
+  EXPECT_EQ(results[0].ip_address_attributes, IP_ADDRESS_ATTRIBUTE_NONE);
+  results.clear();
+
+  // vmware address should be trimmed out if policy specified so.
+  ASSERT_TRUE(FillAdapterAddress(
+      &adapter_address /* adapter_address */, ifname_vm /* ifname */,
+      ipv6_address /* ip_address */, ipv6_prefix /* ip_netmask */,
+      addresses /* sock_addrs */));
+  EXPECT_TRUE(net::internal::GetNetworkListImpl(
+      &results, EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, true, &adapter_address));
+  EXPECT_EQ(results.size(), 0ul);
+  results.clear();
+
+  // Addresses with incompleted DAD should be ignored.
+  ASSERT_TRUE(FillAdapterAddress(
+      &adapter_address /* adapter_address */, ifname_em1 /* ifname */,
+      ipv6_address /* ip_address */, ipv6_prefix /* ip_netmask */,
+      addresses /* sock_addrs */));
+  adapter_address.FirstUnicastAddress->DadState = IpDadStateTentative;
+
+  EXPECT_TRUE(net::internal::GetNetworkListImpl(
+      &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, true, &adapter_address));
+  EXPECT_EQ(results.size(), 0ul);
+  results.clear();
+
+  // Addresses with allowed attribute IpSuffixOriginRandom should be returned
+  // and attributes should be translated correctly to
+  // IP_ADDRESS_ATTRIBUTE_TEMPORARY.
+  ASSERT_TRUE(FillAdapterAddress(
+      &adapter_address /* adapter_address */, ifname_em1 /* ifname */,
+      ipv6_address /* ip_address */, ipv6_prefix /* ip_netmask */,
+      addresses /* sock_addrs */));
+  adapter_address.FirstUnicastAddress->PrefixOrigin =
+      IpPrefixOriginRouterAdvertisement;
+  adapter_address.FirstUnicastAddress->SuffixOrigin = IpSuffixOriginRandom;
+
+  EXPECT_TRUE(net::internal::GetNetworkListImpl(
+      &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, true, &adapter_address));
+  EXPECT_EQ(results.size(), 1ul);
+  EXPECT_EQ(results[0].name, ifname_em1);
+  EXPECT_EQ(results[0].prefix_length, 1ul);
+  EXPECT_EQ(results[0].address, ipv6_address);
+  EXPECT_EQ(results[0].ip_address_attributes, IP_ADDRESS_ATTRIBUTE_TEMPORARY);
+  results.clear();
+
+  // Addresses with preferred lifetime 0 should be returned and
+  // attributes should be translated correctly to
+  // IP_ADDRESS_ATTRIBUTE_DEPRECATED.
+  ASSERT_TRUE(FillAdapterAddress(
+      &adapter_address /* adapter_address */, ifname_em1 /* ifname */,
+      ipv6_address /* ip_address */, ipv6_prefix /* ip_netmask */,
+      addresses /* sock_addrs */));
+  adapter_address.FirstUnicastAddress->PreferredLifetime = 0;
+  adapter_address.FriendlyName = const_cast<PWCHAR>(L"FriendlyInterfaceName");
+  EXPECT_TRUE(net::internal::GetNetworkListImpl(
+      &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, true, &adapter_address));
+  EXPECT_EQ(results.size(), 1ul);
+  EXPECT_EQ(results[0].friendly_name, "FriendlyInterfaceName");
+  EXPECT_EQ(results[0].name, ifname_em1);
+  EXPECT_EQ(results[0].prefix_length, 1ul);
+  EXPECT_EQ(results[0].address, ipv6_address);
+  EXPECT_EQ(results[0].ip_address_attributes, IP_ADDRESS_ATTRIBUTE_DEPRECATED);
+  results.clear();
+}
 
 #endif  // !OS_MACOSX && !OS_WIN && !OS_NACL
 
diff --git a/net/base/net_util_win.cc b/net/base/net_util_win.cc
index 7d146b9..ec40233 100644
--- a/net/base/net_util_win.cc
+++ b/net/base/net_util_win.cc
@@ -85,35 +85,11 @@
       free_memory_func && close_handle_func;
 }
 
-}  // namespace internal
-
-bool GetNetworkList(NetworkInterfaceList* networks, int policy) {
-  // GetAdaptersAddresses() may require IO operations.
-  base::ThreadRestrictions::AssertIOAllowed();
-  bool is_xp = base::win::GetVersion() < base::win::VERSION_VISTA;
-  ULONG len = 0;
-  ULONG flags = is_xp ? GAA_FLAG_INCLUDE_PREFIX : 0;
-  // First get number of networks.
-  ULONG result = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, NULL, &len);
-  if (result != ERROR_BUFFER_OVERFLOW) {
-    // There are 0 networks.
-    return true;
-  }
-  scoped_ptr<char[]> buf(new char[len]);
-  IP_ADAPTER_ADDRESSES *adapters =
-      reinterpret_cast<IP_ADAPTER_ADDRESSES *>(buf.get());
-  result = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, adapters, &len);
-  if (result != NO_ERROR) {
-    LOG(ERROR) << "GetAdaptersAddresses failed: " << result;
-    return false;
-  }
-
-  // These two variables are used below when this method is asked to pick a
-  // IPv6 address which has the shortest lifetime.
-  ULONG ipv6_valid_lifetime = 0;
-  scoped_ptr<NetworkInterface> ipv6_address;
-
-  for (IP_ADAPTER_ADDRESSES *adapter = adapters; adapter != NULL;
+bool GetNetworkListImpl(NetworkInterfaceList* networks,
+                        int policy,
+                        bool is_xp,
+                        const IP_ADAPTER_ADDRESSES* adapters) {
+  for (const IP_ADAPTER_ADDRESSES* adapter = adapters; adapter != NULL;
        adapter = adapter->Next) {
     // Ignore the loopback device.
     if (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK) {
@@ -128,7 +104,7 @@
     // VMware Virtual Ethernet Adapter for VMnet1
     // but don't ignore any GUEST side adapters with a description like:
     // VMware Accelerated AMD PCNet Adapter #2
-    if (policy == EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES &&
+    if ((policy & EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES) &&
         strstr(adapter->AdapterName, "VMnet") != NULL) {
       continue;
     }
@@ -141,7 +117,7 @@
         if (endpoint.FromSockAddr(address->Address.lpSockaddr,
                                   address->Address.iSockaddrLength)) {
           // XP has no OnLinkPrefixLength field.
-          size_t net_prefix = is_xp ? 0 : address->OnLinkPrefixLength;
+          size_t prefix_length = is_xp ? 0 : address->OnLinkPrefixLength;
           if (is_xp) {
             // Prior to Windows Vista the FirstPrefix pointed to the list with
             // single prefix for each IP address assigned to the adapter.
@@ -157,52 +133,72 @@
                   IPNumberMatchesPrefix(endpoint.address(),
                                         network_endpoint.address(),
                                         prefix->PrefixLength)) {
-                net_prefix = std::max<size_t>(net_prefix, prefix->PrefixLength);
+                prefix_length =
+                    std::max<size_t>(prefix_length, prefix->PrefixLength);
               }
             }
           }
+
+          // If the duplicate address detection (DAD) state is not changed to
+          // Preferred, skip this address.
+          if (address->DadState != IpDadStatePreferred) {
+            continue;
+          }
+
           uint32 index =
               (family == AF_INET) ? adapter->IfIndex : adapter->Ipv6IfIndex;
-          // Pick one IPv6 address with least valid lifetime.
-          // The reason we are checking |ValidLifeftime| as there is no other
-          // way identifying the interface type. Usually (and most likely) temp
-          // IPv6 will have a shorter ValidLifetime value then the permanent
-          // interface.
-          if (family == AF_INET6 &&
-              (policy & INCLUDE_ONLY_TEMP_IPV6_ADDRESS_IF_POSSIBLE)) {
-            if (ipv6_valid_lifetime == 0 ||
-                ipv6_valid_lifetime > address->ValidLifetime) {
-              ipv6_valid_lifetime = address->ValidLifetime;
-              ipv6_address.reset(new NetworkInterface(
-                  adapter->AdapterName,
-                  base::SysWideToNativeMB(adapter->FriendlyName),
-                  index,
-                  GetNetworkInterfaceType(adapter->IfType),
-                  endpoint.address(),
-                  net_prefix,
-                  IP_ADDRESS_ATTRIBUTE_NONE));
-              continue;
+
+          // From http://technet.microsoft.com/en-us/ff568768(v=vs.60).aspx, the
+          // way to identify a temporary IPv6 Address is to check if
+          // PrefixOrigin is equal to IpPrefixOriginRouterAdvertisement and
+          // SuffixOrigin equal to IpSuffixOriginRandom.
+          int ip_address_attributes = IP_ADDRESS_ATTRIBUTE_NONE;
+          if (family == AF_INET6) {
+            if (address->PrefixOrigin == IpPrefixOriginRouterAdvertisement &&
+                address->SuffixOrigin == IpSuffixOriginRandom) {
+              ip_address_attributes |= IP_ADDRESS_ATTRIBUTE_TEMPORARY;
+            }
+            if (address->PreferredLifetime == 0) {
+              ip_address_attributes |= IP_ADDRESS_ATTRIBUTE_DEPRECATED;
             }
           }
-          networks->push_back(
-              NetworkInterface(adapter->AdapterName,
-                               base::SysWideToNativeMB(adapter->FriendlyName),
-                               index,
-                               GetNetworkInterfaceType(adapter->IfType),
-                               endpoint.address(),
-                               net_prefix,
-                               IP_ADDRESS_ATTRIBUTE_NONE));
+          networks->push_back(NetworkInterface(
+              adapter->AdapterName,
+              base::SysWideToNativeMB(adapter->FriendlyName), index,
+              GetNetworkInterfaceType(adapter->IfType), endpoint.address(),
+              prefix_length, ip_address_attributes));
         }
       }
     }
   }
-
-  if (ipv6_address.get()) {
-    networks->push_back(*(ipv6_address.get()));
-  }
   return true;
 }
 
+}  // namespace internal
+
+bool GetNetworkList(NetworkInterfaceList* networks, int policy) {
+  bool is_xp = base::win::GetVersion() < base::win::VERSION_VISTA;
+  ULONG len = 0;
+  ULONG flags = is_xp ? GAA_FLAG_INCLUDE_PREFIX : 0;
+  // GetAdaptersAddresses() may require IO operations.
+  base::ThreadRestrictions::AssertIOAllowed();
+  ULONG result = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, NULL, &len);
+  if (result != ERROR_BUFFER_OVERFLOW) {
+    // There are 0 networks.
+    return true;
+  }
+  scoped_ptr<char[]> buf(new char[len]);
+  IP_ADAPTER_ADDRESSES* adapters =
+      reinterpret_cast<IP_ADAPTER_ADDRESSES*>(buf.get());
+  result = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, adapters, &len);
+  if (result != NO_ERROR) {
+    LOG(ERROR) << "GetAdaptersAddresses failed: " << result;
+    return false;
+  }
+
+  return internal::GetNetworkListImpl(networks, policy, is_xp, adapters);
+}
+
 WifiPHYLayerProtocol GetWifiPHYLayerProtocol() {
   const internal::WlanApi& wlanapi = internal::WlanApi::GetInstance();
   if (!wlanapi.initialized)
diff --git a/net/base/net_util_win.h b/net/base/net_util_win.h
index afa888b..b0c2dd6 100644
--- a/net/base/net_util_win.h
+++ b/net/base/net_util_win.h
@@ -8,10 +8,12 @@
 // This file is only used to expose some of the internals
 // of net_util_win.cc to tests.
 
+#include <iphlpapi.h>
 #include <wlanapi.h>
 
 #include "base/win/scoped_handle.h"
 #include "net/base/net_export.h"
+#include "net/base/net_util.h"
 
 namespace net {
 namespace internal {
@@ -78,6 +80,12 @@
   }
 };
 
+NET_EXPORT bool GetNetworkListImpl(
+    NetworkInterfaceList* networks,
+    int policy,
+    bool is_xp,
+    const IP_ADAPTER_ADDRESSES* ip_adapter_addresses);
+
 }  // namespace internal
 
 }  // namespace net
diff --git a/net/base/network_delegate.cc b/net/base/network_delegate.cc
index 5b69cfb..d4aa19e 100644
--- a/net/base/network_delegate.cc
+++ b/net/base/network_delegate.cc
@@ -339,12 +339,6 @@
   return false;
 }
 
-int NetworkDelegate::OnBeforeSocketStreamConnect(
-    SocketStream* socket,
-    const CompletionCallback& callback) {
-  return OK;
-}
-
 bool NetworkDelegate::OnCancelURLRequestWithPolicyViolatingReferrerHeader(
     const URLRequest& request,
     const GURL& target_url,
diff --git a/net/base/network_delegate.h b/net/base/network_delegate.h
index 03dee0b..a169fc6 100644
--- a/net/base/network_delegate.h
+++ b/net/base/network_delegate.h
@@ -38,7 +38,6 @@
 class ProxyInfo;
 class ProxyServer;
 class ProxyService;
-class SocketStream;
 class URLRequest;
 
 class NET_EXPORT NetworkDelegate : public base::NonThreadSafe {
@@ -268,11 +267,6 @@
       const GURL& url,
       const GURL& first_party_for_cookies) const;
 
-  // Called before a SocketStream tries to connect.
-  // See OnBeforeURLRequest for return value description. Returns OK by default.
-  virtual int OnBeforeSocketStreamConnect(
-      SocketStream* socket, const CompletionCallback& callback);
-
   // Called when the |referrer_url| for requesting |target_url| during handling
   // of the |request| is does not comply with the referrer policy (e.g. a
   // secure referrer for an insecure initial target).
diff --git a/net/base/sdch_manager.cc b/net/base/sdch_manager.cc
index af5e6ee..1aa9627 100644
--- a/net/base/sdch_manager.cc
+++ b/net/base/sdch_manager.cc
@@ -9,6 +9,7 @@
 #include "base/metrics/histogram.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
+#include "base/time/default_clock.h"
 #include "base/values.h"
 #include "crypto/sha2.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
@@ -38,9 +39,6 @@
 
 namespace net {
 
-//------------------------------------------------------------------------------
-// static
-
 // Adjust SDCH limits downwards for mobile.
 #if defined(OS_ANDROID) || defined(OS_IOS)
 // static
@@ -58,7 +56,6 @@
 // static
 bool SdchManager::g_secure_scheme_supported_ = true;
 
-//------------------------------------------------------------------------------
 SdchManager::Dictionary::Dictionary(const std::string& dictionary_text,
                                     size_t offset,
                                     const std::string& client_hash,
@@ -73,45 +70,22 @@
       domain_(domain),
       path_(path),
       expiration_(expiration),
-      ports_(ports) {
+      ports_(ports),
+      clock_(new base::DefaultClock) {
 }
 
-SdchManager::Dictionary::~Dictionary() {
-}
+SdchManager::Dictionary::Dictionary(const SdchManager::Dictionary& rhs)
+    : text_(rhs.text_),
+      client_hash_(rhs.client_hash_),
+      url_(rhs.url_),
+      domain_(rhs.domain_),
+      path_(rhs.path_),
+      expiration_(rhs.expiration_),
+      ports_(rhs.ports_),
+      clock_(new base::DefaultClock) {}
 
-SdchProblemCode SdchManager::Dictionary::CanAdvertise(
-    const GURL& target_url) const {
-  /* The specific rules of when a dictionary should be advertised in an
-     Avail-Dictionary header are modeled after the rules for cookie scoping. The
-     terms "domain-match" and "pathmatch" are defined in RFC 2965 [6]. A
-     dictionary may be advertised in the Avail-Dictionaries header exactly when
-     all of the following are true:
-      1. The server's effective host name domain-matches the Domain attribute of
-         the dictionary.
-      2. If the dictionary has a Port attribute, the request port is one of the
-         ports listed in the Port attribute.
-      3. The request URI path-matches the path header of the dictionary.
-      4. The request is not an HTTPS request.
-     We can override (ignore) item (4) only when we have explicitly enabled
-     HTTPS support AND the dictionary acquisition scheme matches the target
-     url scheme.
-    */
-  if (!DomainMatch(target_url, domain_))
-    return SDCH_DICTIONARY_FOUND_HAS_WRONG_DOMAIN;
-  if (!ports_.empty() && 0 == ports_.count(target_url.EffectiveIntPort()))
-    return SDCH_DICTIONARY_FOUND_HAS_WRONG_PORT_LIST;
-  if (path_.size() && !PathMatch(target_url.path(), path_))
-    return SDCH_DICTIONARY_FOUND_HAS_WRONG_PATH;
-  if (!SdchManager::secure_scheme_supported() && target_url.SchemeIsSecure())
-    return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME;
-  if (target_url.SchemeIsSecure() != url_.SchemeIsSecure())
-    return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME;
-  if (base::Time::Now() > expiration_)
-    return SDCH_DICTIONARY_FOUND_EXPIRED;
-  return SDCH_OK;
-}
+SdchManager::Dictionary::~Dictionary() {}
 
-//------------------------------------------------------------------------------
 // Security functions restricting loads and use of dictionaries.
 
 // static
@@ -168,7 +142,7 @@
 }
 
 SdchProblemCode SdchManager::Dictionary::CanUse(
-    const GURL& referring_url) const {
+    const GURL& target_url) const {
   /*
     1. The request URL's host name domain-matches the Domain attribute of the
       dictionary.
@@ -180,24 +154,24 @@
     HTTPS support AND the dictionary acquisition scheme matches the target
      url scheme.
   */
-  if (!DomainMatch(referring_url, domain_))
+  if (!DomainMatch(target_url, domain_))
     return SDCH_DICTIONARY_FOUND_HAS_WRONG_DOMAIN;
 
-  if (!ports_.empty() && 0 == ports_.count(referring_url.EffectiveIntPort()))
+  if (!ports_.empty() && 0 == ports_.count(target_url.EffectiveIntPort()))
     return SDCH_DICTIONARY_FOUND_HAS_WRONG_PORT_LIST;
 
-  if (path_.size() && !PathMatch(referring_url.path(), path_))
+  if (path_.size() && !PathMatch(target_url.path(), path_))
     return SDCH_DICTIONARY_FOUND_HAS_WRONG_PATH;
 
-  if (!SdchManager::secure_scheme_supported() && referring_url.SchemeIsSecure())
+  if (!SdchManager::secure_scheme_supported() && target_url.SchemeIsSecure())
     return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME;
 
-  if (referring_url.SchemeIsSecure() != url_.SchemeIsSecure())
+  if (target_url.SchemeIsSecure() != url_.SchemeIsSecure())
     return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME;
 
   // TODO(jar): Remove overly restrictive failsafe test (added per security
   // review) when we have a need to be more general.
-  if (!referring_url.SchemeIsHTTPOrHTTPS())
+  if (!target_url.SchemeIsHTTPOrHTTPS())
     return SDCH_ATTEMPT_TO_DECODE_NON_HTTP_DATA;
 
   return SDCH_OK;
@@ -228,7 +202,54 @@
   return gurl.DomainIs(restriction.data(), restriction.size());
 }
 
-//------------------------------------------------------------------------------
+bool SdchManager::Dictionary::Expired() const {
+  return clock_->Now() > expiration_;
+}
+
+void SdchManager::Dictionary::SetClockForTesting(
+    scoped_ptr<base::Clock> clock) {
+  clock_ = clock.Pass();
+}
+
+SdchManager::DictionarySet::DictionarySet() {}
+
+SdchManager::DictionarySet::~DictionarySet() {}
+
+std::string SdchManager::DictionarySet::GetDictionaryClientHashList() const {
+  std::string result;
+  bool first = true;
+  for (const auto& entry: dictionaries_) {
+    if (!first)
+      result.append(",");
+
+    result.append(entry.second->data.client_hash());
+    first = false;
+  }
+  return result;
+}
+
+const SdchManager::Dictionary* SdchManager::DictionarySet::GetDictionary(
+    const std::string& hash) const {
+  auto it = dictionaries_.find(hash);
+  if (it == dictionaries_.end())
+    return NULL;
+
+  return &it->second->data;
+}
+
+bool SdchManager::DictionarySet::Empty() const {
+  return dictionaries_.empty();
+}
+
+void SdchManager::DictionarySet::AddDictionary(
+    const std::string& server_hash,
+    const scoped_refptr<base::RefCountedData<SdchManager::Dictionary>>&
+    dictionary) {
+  DCHECK(dictionaries_.end() == dictionaries_.find(server_hash));
+
+  dictionaries_[server_hash] = dictionary;
+}
+
 SdchManager::SdchManager() {
   DCHECK(thread_checker_.CalledOnValidThread());
 }
@@ -236,7 +257,7 @@
 SdchManager::~SdchManager() {
   DCHECK(thread_checker_.CalledOnValidThread());
   while (!dictionaries_.empty()) {
-    DictionaryMap::iterator it = dictionaries_.begin();
+    auto it = dictionaries_.begin();
     dictionaries_.erase(it->first);
   }
 }
@@ -246,7 +267,7 @@
   allow_latency_experiment_.clear();
 
   // Note that this may result in not having dictionaries we've advertised
-  // for incoming responses.  The window is relatively small (as ClearData()
+  // for incoming responses. The window is relatively small (as ClearData()
   // is not expected to be called frequently), so we rely on meta-refresh
   // to handle this case.
   dictionaries_.clear();
@@ -386,7 +407,7 @@
        3 The parent domain of the referrer URL host name is not a top level
            domain
    */
-  // Item (1) above implies item (2).  Spec should be updated.
+  // Item (1) above implies item (2). Spec should be updated.
   // I take "host name match" to be "is identical to"
   if (referring_url.host() != dictionary_url.host() ||
       referring_url.scheme() != dictionary_url.scheme())
@@ -403,51 +424,49 @@
   return SDCH_OK;
 }
 
-SdchProblemCode SdchManager::GetVcdiffDictionary(
-    const std::string& server_hash,
-    const GURL& referring_url,
-    scoped_refptr<Dictionary>* dictionary) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  *dictionary = NULL;
-  DictionaryMap::iterator it = dictionaries_.find(server_hash);
-  if (it == dictionaries_.end())
-    return SDCH_DICTIONARY_HASH_NOT_FOUND;
+scoped_ptr<SdchManager::DictionarySet>
+SdchManager::GetDictionarySet(const GURL& target_url) {
+  if (IsInSupportedDomain(target_url) != SDCH_OK)
+    return NULL;
 
-  scoped_refptr<Dictionary> matching_dictionary = it->second;
-
-  SdchProblemCode rv = IsInSupportedDomain(referring_url);
-  if (rv != SDCH_OK)
-    return rv;
-
-  rv = matching_dictionary->CanUse(referring_url);
-  if (rv == SDCH_OK)
-    *dictionary = matching_dictionary;
-  return rv;
-}
-
-// TODO(jar): If we have evictions from the dictionaries_, then we need to
-// change this interface to return a list of reference counted Dictionary
-// instances that can be used if/when a server specifies one.
-void SdchManager::GetAvailDictionaryList(const GURL& target_url,
-                                         std::string* list) {
-  DCHECK(thread_checker_.CalledOnValidThread());
   int count = 0;
-  for (DictionaryMap::iterator it = dictionaries_.begin();
-       it != dictionaries_.end(); ++it) {
-    SdchProblemCode rv = IsInSupportedDomain(target_url);
-    if (rv != SDCH_OK)
+  scoped_ptr<SdchManager::DictionarySet> result(new DictionarySet);
+  for (const auto& entry: dictionaries_) {
+    if (entry.second->data.CanUse(target_url) != SDCH_OK)
       continue;
-
-    if (it->second->CanAdvertise(target_url) != SDCH_OK)
+    if (entry.second->data.Expired())
       continue;
     ++count;
-    if (!list->empty())
-      list->append(",");
-    list->append(it->second->client_hash());
+    result->AddDictionary(entry.first, entry.second);
   }
-  // Watch to see if we have corrupt or numerous dictionaries.
-  if (count > 0)
-    UMA_HISTOGRAM_COUNTS("Sdch3.Advertisement_Count", count);
+
+  if (count == 0)
+    return NULL;
+
+  UMA_HISTOGRAM_COUNTS("Sdch3.Advertisement_Count", count);
+
+  return result.Pass();
+}
+
+scoped_ptr<SdchManager::DictionarySet>
+SdchManager::GetDictionarySetByHash(
+    const GURL& target_url,
+    const std::string& server_hash,
+    SdchProblemCode* problem_code) {
+  scoped_ptr<SdchManager::DictionarySet> result;
+
+  *problem_code = SDCH_DICTIONARY_HASH_NOT_FOUND;
+  const auto& it = dictionaries_.find(server_hash);
+  if (it == dictionaries_.end())
+    return result;
+
+  *problem_code = it->second->data.CanUse(target_url);
+  if (*problem_code != SDCH_OK)
+    return result;
+
+  result.reset(new DictionarySet);
+  result->AddDictionary(it->first, it->second);
+  return result;
 }
 
 // static
@@ -465,7 +484,6 @@
   DCHECK_EQ(client_hash->length(), 8u);
 }
 
-//------------------------------------------------------------------------------
 // Methods for supporting latency experiments.
 
 bool SdchManager::AllowLatencyExperiment(const GURL& url) const {
@@ -575,8 +593,8 @@
     return rv;
 
   // TODO(jar): Remove these hacks to preclude a DOS attack involving piles of
-  // useless dictionaries.  We should probably have a cache eviction plan,
-  // instead of just blocking additions.  For now, with the spec in flux, it
+  // useless dictionaries. We should probably have a cache eviction plan,
+  // instead of just blocking additions. For now, with the spec in flux, it
   // is probably not worth doing eviction handling.
   if (kMaxDictionarySize < dictionary_text.size())
     return SDCH_DICTIONARY_IS_TOO_LARGE;
@@ -587,15 +605,22 @@
   UMA_HISTOGRAM_COUNTS("Sdch3.Dictionary size loaded", dictionary_text.size());
   DVLOG(1) << "Loaded dictionary with client hash " << client_hash
            << " and server hash " << server_hash;
-  Dictionary* dictionary =
-      new Dictionary(dictionary_text, header_end + 2, client_hash,
-                     dictionary_url_normalized, domain,
-                     path, expiration, ports);
-  dictionaries_[server_hash] = dictionary;
+  Dictionary dictionary(dictionary_text, header_end + 2, client_hash,
+                        dictionary_url_normalized, domain, path, expiration,
+                        ports);
+  dictionaries_[server_hash] =
+      new base::RefCountedData<Dictionary>(dictionary);
+
   return SDCH_OK;
 }
 
 // static
+scoped_ptr<SdchManager::DictionarySet>
+SdchManager::CreateEmptyDictionarySetForTesting() {
+  return scoped_ptr<DictionarySet>(new DictionarySet).Pass();
+}
+
+// static
 void SdchManager::UrlSafeBase64Encode(const std::string& input,
                                       std::string* output) {
   // Since this is only done during a dictionary load, and hashes are only 8
@@ -612,20 +637,20 @@
   value->SetBoolean("secure_scheme_support", secure_scheme_supported());
 
   base::ListValue* entry_list = new base::ListValue();
-  for (DictionaryMap::const_iterator it = dictionaries_.begin();
-       it != dictionaries_.end(); ++it) {
+  for (const auto& entry: dictionaries_) {
     base::DictionaryValue* entry_dict = new base::DictionaryValue();
-    entry_dict->SetString("url", it->second->url().spec());
-    entry_dict->SetString("client_hash", it->second->client_hash());
-    entry_dict->SetString("domain", it->second->domain());
-    entry_dict->SetString("path", it->second->path());
+    entry_dict->SetString("url", entry.second->data.url().spec());
+    entry_dict->SetString("client_hash", entry.second->data.client_hash());
+    entry_dict->SetString("domain", entry.second->data.domain());
+    entry_dict->SetString("path", entry.second->data.path());
     base::ListValue* port_list = new base::ListValue();
-    for (std::set<int>::const_iterator port_it = it->second->ports().begin();
-         port_it != it->second->ports().end(); ++port_it) {
+    for (std::set<int>::const_iterator port_it =
+             entry.second->data.ports().begin();
+         port_it != entry.second->data.ports().end(); ++port_it) {
       port_list->AppendInteger(*port_it);
     }
     entry_dict->Set("ports", port_list);
-    entry_dict->SetString("server_hash", it->first);
+    entry_dict->SetString("server_hash", entry.first);
     entry_list->Append(entry_dict);
   }
   value->Set("dictionaries", entry_list);
diff --git a/net/base/sdch_manager.h b/net/base/sdch_manager.h
index 016978a..0948b4c 100644
--- a/net/base/sdch_manager.h
+++ b/net/base/sdch_manager.h
@@ -2,12 +2,23 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// This file contains the SdchManager class and two nested classes
+// (Dictionary, DictionarySet). SdchManager::Dictionary contains all
+// of the information about an SDCH dictionary. The manager is
+// responsible for storing those dictionaries, and provides access to
+// them through DictionarySet objects. A DictionarySet is an object
+// whose lifetime is under the control of the consumer. It is a
+// reference to a set of dictionaries, and guarantees that none of
+// those dictionaries will be destroyed while the DictionarySet
+// reference is alive.
+
 #ifndef NET_BASE_SDCH_MANAGER_H_
 #define NET_BASE_SDCH_MANAGER_H_
 
 #include <map>
 #include <set>
 #include <string>
+#include <vector>
 
 #include "base/gtest_prod_util.h"
 #include "base/memory/ref_counted.h"
@@ -20,6 +31,7 @@
 #include "url/gurl.h"
 
 namespace base {
+class Clock;
 class Value;
 }
 
@@ -38,25 +50,22 @@
 // These dictionaries are acquired over the net, and include a header
 // (containing metadata) as well as a VCDIFF dictionary (for use by a VCDIFF
 // module) to decompress data.
+//
+// A dictionary held by the manager may nonetheless outlive the manager if
+// a DictionarySet object refers to it; see below.
 class NET_EXPORT SdchManager {
  public:
+  class Dictionary;
+  typedef std::map<std::string, scoped_refptr<base::RefCountedData<Dictionary>>>
+      DictionaryMap;
+
   // Use the following static limits to block DOS attacks until we implement
   // a cached dictionary evicition strategy.
   static const size_t kMaxDictionarySize;
   static const size_t kMaxDictionaryCount;
 
-  // There is one instance of |Dictionary| for each memory-cached SDCH
-  // dictionary.
-  class NET_EXPORT_PRIVATE Dictionary : public base::RefCounted<Dictionary> {
+  class NET_EXPORT_PRIVATE Dictionary {
    public:
-    // Sdch filters can get our text to use in decoding compressed data.
-    const std::string& text() const { return text_; }
-
-   private:
-    friend class base::RefCounted<Dictionary>;
-    friend class SdchManager;  // Only manager can construct an instance.
-    FRIEND_TEST_ALL_PREFIXES(SdchManagerTest, PathMatch);
-
     // Construct a vc-diff usable dictionary from the dictionary_text starting
     // at the given offset. The supplied client_hash should be used to
     // advertise the dictionary's availability relative to the suppplied URL.
@@ -68,7 +77,11 @@
                const std::string& path,
                const base::Time& expiration,
                const std::set<int>& ports);
-    virtual ~Dictionary();
+
+    ~Dictionary();
+
+    // Sdch filters can get our text to use in decoding compressed data.
+    const std::string& text() const { return text_; }
 
     const GURL& url() const { return url_; }
     const std::string& client_hash() const { return client_hash_; }
@@ -77,10 +90,6 @@
     const base::Time& expiration() const { return expiration_; }
     const std::set<int>& ports() const { return ports_; }
 
-    // Security method to check if we can advertise this dictionary for use
-    // if the |target_url| returns SDCH compressed data.
-    SdchProblemCode CanAdvertise(const GURL& target_url) const;
-
     // Security methods to check if we can establish a new dictionary with the
     // given data, that arrived in response to get of dictionary_url.
     static SdchProblemCode CanSet(const std::string& domain,
@@ -99,6 +108,19 @@
     // Compare domains to see if the "match" for dictionary use.
     static bool DomainMatch(const GURL& url, const std::string& restriction);
 
+    // Is this dictionary expired?
+    bool Expired() const;
+
+    void SetClockForTesting(scoped_ptr<base::Clock> clock);
+
+   private:
+    friend class base::RefCountedData<Dictionary>;
+
+    // Private copy-constructor to support RefCountedData<>, which requires
+    // that an object stored in it be either DefaultConstructible or
+    // CopyConstructible
+    Dictionary(const Dictionary& rhs);
+
     // The actual text of the dictionary.
     std::string text_;
 
@@ -118,7 +140,40 @@
     const base::Time expiration_;  // Implied by max-age.
     const std::set<int> ports_;
 
-    DISALLOW_COPY_AND_ASSIGN(Dictionary);
+    scoped_ptr<base::Clock> clock_;
+
+    void operator=(const Dictionary&) = delete;
+  };
+
+  // A handle for one or more dictionaries which will keep the dictionaries
+  // alive and accessible for the handle's lifetime.
+  class NET_EXPORT_PRIVATE DictionarySet {
+   public:
+    ~DictionarySet();
+
+    // Return a comma separated list of client hashes.
+    std::string GetDictionaryClientHashList() const;
+
+    // Lookup a given dictionary based on server hash. Returned pointer
+    // is guaranteed to be valid for the lifetime of the DictionarySet.
+    // Returns NULL if hash is not a valid server hash for a dictionary
+    // named by DictionarySet.
+    const SdchManager::Dictionary* GetDictionary(const std::string& hash) const;
+
+    bool Empty() const;
+
+   private:
+    // A DictionarySet may only be constructed by the SdchManager.
+    friend class SdchManager;
+
+    DictionarySet();
+    void AddDictionary(const std::string& server_hash,
+                       const scoped_refptr<base::RefCountedData<
+                           SdchManager::Dictionary>>& dictionary);
+
+    DictionaryMap dictionaries_;
+
+    DISALLOW_COPY_AND_ASSIGN(DictionarySet);
   };
 
   SdchManager();
@@ -178,23 +233,22 @@
   SdchProblemCode OnGetDictionary(const GURL& request_url,
                                   const GURL& dictionary_url);
 
-  // Find the vcdiff dictionary (the body of the sdch dictionary that appears
-  // after the meta-data headers like Domain:...) with the given |server_hash|
-  // to use to decompreses data that arrived as SDCH encoded content. Check to
-  // be sure the returned |dictionary| can be used for decoding content supplied
-  // in response to a request for |referring_url|.
-  // Return null in |dictionary| if there is no matching legal dictionary.
-  // Returns SDCH_OK if dictionary is not found, SDCH(-over-https) is disabled,
-  // or if matching legal dictionary exists. Otherwise returns the
-  // corresponding problem code.
-  SdchProblemCode GetVcdiffDictionary(const std::string& server_hash,
-                                      const GURL& referring_url,
-                                      scoped_refptr<Dictionary>* dictionary);
+  // Get a handle to the available dictionaries that might be used
+  // for encoding responses for the given URL. The return set will not
+  // include expired dictionaries. If no dictionaries
+  // are appropriate to use with the target_url, NULL is returned.
+  scoped_ptr<DictionarySet> GetDictionarySet(const GURL& target_url);
 
-  // Get list of available (pre-cached) dictionaries that we have already loaded
-  // into memory. The list is a comma separated list of (client) hashes per
-  // the SDCH spec.
-  void GetAvailDictionaryList(const GURL& target_url, std::string* list);
+  // Get a handle to a specific dictionary, by its server hash, confirming
+  // that that specific dictionary is appropriate to use with |target_url|.
+  // Expired dictionaries will be returned. If no dictionary with that
+  // hash exists that is usable with |target_url|, NULL is returned.
+  // If there is a usability problem, |*error_code| is set to the
+  // appropriate problem code.
+  scoped_ptr<DictionarySet> GetDictionarySetByHash(
+      const GURL& target_url,
+      const std::string& server_hash,
+      SdchProblemCode* problem_code);
 
   // Construct the pair of hashes for client and server to identify an SDCH
   // dictionary. This is only made public to facilitate unit testing, but is
@@ -225,6 +279,8 @@
   void AddObserver(SdchObserver* observer);
   void RemoveObserver(SdchObserver* observer);
 
+  static scoped_ptr<DictionarySet> CreateEmptyDictionarySetForTesting();
+
  private:
   struct BlacklistInfo {
     BlacklistInfo() : count(0), exponential_count(0), reason(SDCH_OK) {}
@@ -233,18 +289,16 @@
     int exponential_count;   // Current exponential backoff ratchet.
     SdchProblemCode reason;  // Why domain was blacklisted.
   };
+
   typedef std::map<std::string, BlacklistInfo> DomainBlacklistInfo;
   typedef std::set<std::string> ExperimentSet;
 
   // Determines whether a "Get-Dictionary" header is legal (dictionary
   // url has appropriate relationship to referrer url) in the SDCH
-  // protocol.  Return SDCH_OK if fetch is legal.
+  // protocol. Return SDCH_OK if fetch is legal.
   SdchProblemCode CanFetchDictionary(const GURL& referring_url,
                                      const GURL& dictionary_url) const;
 
-  // A map of dictionaries info indexed by the hash that the server provides.
-  typedef std::map<std::string, scoped_refptr<Dictionary> > DictionaryMap;
-
   // Support SDCH compression, by advertising in headers.
   static bool g_sdch_enabled_;
 
diff --git a/net/base/sdch_manager_unittest.cc b/net/base/sdch_manager_unittest.cc
index c20be58..2b78394 100644
--- a/net/base/sdch_manager_unittest.cc
+++ b/net/base/sdch_manager_unittest.cc
@@ -8,6 +8,8 @@
 
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/simple_test_clock.h"
 #include "net/base/net_log.h"
 #include "net/base/sdch_manager.h"
 #include "net/base/sdch_observer.h"
@@ -199,12 +201,9 @@
   EXPECT_TRUE(AddSdchDictionary(dictionary_text,
                                 GURL("http://" + dictionary_domain)));
 
-  std::string dictionary_list;
   // HTTP target URL can advertise dictionary.
-  sdch_manager()->GetAvailDictionaryList(
-      GURL("http://" + dictionary_domain + "/test"),
-      &dictionary_list);
-  EXPECT_FALSE(dictionary_list.empty());
+  EXPECT_TRUE(sdch_manager()->GetDictionarySet(
+      GURL("http://" + dictionary_domain + "/test")));
 }
 
 TEST_F(SdchManagerTest, CanNotAdvertiseDictionaryOverHTTPS) {
@@ -214,12 +213,9 @@
   EXPECT_TRUE(AddSdchDictionary(dictionary_text,
                                 GURL("http://" + dictionary_domain)));
 
-  std::string dictionary_list;
   // HTTPS target URL should NOT advertise dictionary.
-  sdch_manager()->GetAvailDictionaryList(
-      GURL("https://" + dictionary_domain + "/test"),
-      &dictionary_list);
-  EXPECT_TRUE(dictionary_list.empty());
+  EXPECT_FALSE(sdch_manager()->GetDictionarySet(
+      GURL("https://" + dictionary_domain + "/test")));
 }
 
 TEST_F(SdchManagerTest, CanUseHTTPSDictionaryOverHTTPSIfEnabled) {
@@ -234,20 +230,21 @@
                                 GURL("https://" + dictionary_domain)));
 
   GURL target_url("https://" + dictionary_domain + "/test");
-  std::string dictionary_list;
   // HTTPS target URL should advertise dictionary if secure scheme support is
   // enabled.
-  sdch_manager()->GetAvailDictionaryList(target_url, &dictionary_list);
-  EXPECT_FALSE(dictionary_list.empty());
+  EXPECT_TRUE(sdch_manager()->GetDictionarySet(target_url));
 
   // Dictionary should be available.
-  scoped_refptr<SdchManager::Dictionary> dictionary;
   std::string client_hash;
   std::string server_hash;
   sdch_manager()->GenerateHash(dictionary_text, &client_hash, &server_hash);
-  EXPECT_EQ(SDCH_OK, sdch_manager()->GetVcdiffDictionary(
-                         server_hash, target_url, &dictionary));
-  EXPECT_TRUE(dictionary.get() != NULL);
+  SdchProblemCode problem_code;
+  scoped_ptr<SdchManager::DictionarySet> dict_set(
+      sdch_manager()->GetDictionarySetByHash(
+          target_url, server_hash, &problem_code));
+  EXPECT_EQ(SDCH_OK, problem_code);
+  EXPECT_TRUE(dict_set.get());
+  EXPECT_TRUE(dict_set->GetDictionary(server_hash));
 }
 
 TEST_F(SdchManagerTest, CanNotUseHTTPDictionaryOverHTTPS) {
@@ -258,21 +255,20 @@
                                 GURL("http://" + dictionary_domain)));
 
   GURL target_url("https://" + dictionary_domain + "/test");
-  std::string dictionary_list;
   // HTTPS target URL should not advertise dictionary acquired over HTTP even if
   // secure scheme support is enabled.
   SdchManager::EnableSecureSchemeSupport(true);
-  sdch_manager()->GetAvailDictionaryList(target_url, &dictionary_list);
-  EXPECT_TRUE(dictionary_list.empty());
+  EXPECT_FALSE(sdch_manager()->GetDictionarySet(target_url));
 
-  scoped_refptr<SdchManager::Dictionary> dictionary;
   std::string client_hash;
   std::string server_hash;
   sdch_manager()->GenerateHash(dictionary_text, &client_hash, &server_hash);
-  EXPECT_EQ(SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME,
-            sdch_manager()->GetVcdiffDictionary(server_hash, target_url,
-                                                &dictionary));
-  EXPECT_TRUE(dictionary.get() == NULL);
+  SdchProblemCode problem_code;
+  scoped_ptr<SdchManager::DictionarySet> dict_set(
+      sdch_manager()->GetDictionarySetByHash(
+          target_url, server_hash, &problem_code));
+  EXPECT_FALSE(dict_set.get());
+  EXPECT_EQ(SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME, problem_code);
 }
 
 TEST_F(SdchManagerTest, CanNotUseHTTPSDictionaryOverHTTP) {
@@ -284,20 +280,19 @@
                                 GURL("https://" + dictionary_domain)));
 
   GURL target_url("http://" + dictionary_domain + "/test");
-  std::string dictionary_list;
   // HTTP target URL should not advertise dictionary acquired over HTTPS even if
   // secure scheme support is enabled.
-  sdch_manager()->GetAvailDictionaryList(target_url, &dictionary_list);
-  EXPECT_TRUE(dictionary_list.empty());
+  EXPECT_FALSE(sdch_manager()->GetDictionarySet(target_url));
 
-  scoped_refptr<SdchManager::Dictionary> dictionary;
   std::string client_hash;
   std::string server_hash;
   sdch_manager()->GenerateHash(dictionary_text, &client_hash, &server_hash);
-  EXPECT_EQ(SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME,
-            sdch_manager()->GetVcdiffDictionary(server_hash, target_url,
-                                                &dictionary));
-  EXPECT_TRUE(dictionary.get() == NULL);
+  SdchProblemCode problem_code;
+  scoped_ptr<SdchManager::DictionarySet> dict_set(
+      sdch_manager()->GetDictionarySetByHash(
+          target_url, server_hash, &problem_code));
+  EXPECT_FALSE(dict_set.get());
+  EXPECT_EQ(SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME, problem_code);
 }
 
 TEST_F(SdchManagerTest, FailToSetDomainMismatchDictionary) {
@@ -438,7 +433,7 @@
   EXPECT_TRUE(PathMatch("/search/", "/search/"));
 
   // Prefix only works if last character of restriction is a slash, or first
-  // character in path after a match is a slash.  Validate each case separately.
+  // character in path after a match is a slash. Validate each case separately.
 
   // Rely on the slash in the path (not at the end of the restriction).
   EXPECT_TRUE(PathMatch("/search/something", "/search"));
@@ -519,34 +514,36 @@
   // can't get them from the other.
   EXPECT_TRUE(AddSdchDictionary(dictionary_text_1,
                                 GURL("http://" + dictionary_domain_1)));
-  scoped_refptr<SdchManager::Dictionary> dictionary;
-  EXPECT_EQ(SDCH_OK, sdch_manager()->GetVcdiffDictionary(
-                         server_hash_1,
-                         GURL("http://" + dictionary_domain_1 + "/random_url"),
-                         &dictionary));
-  EXPECT_TRUE(dictionary.get());
+  scoped_ptr<SdchManager::DictionarySet> dict_set;
+
+  SdchProblemCode problem_code;
+  dict_set = sdch_manager()->GetDictionarySetByHash(
+      GURL("http://" + dictionary_domain_1 + "/random_url"),
+      server_hash_1, &problem_code);
+  EXPECT_TRUE(dict_set);
+  EXPECT_TRUE(dict_set->GetDictionary(server_hash_1));
+  EXPECT_EQ(SDCH_OK, problem_code);
 
   second_manager.AddSdchDictionary(
       dictionary_text_2, GURL("http://" + dictionary_domain_2));
-  second_manager.GetVcdiffDictionary(
-      server_hash_2,
+  dict_set = second_manager.GetDictionarySetByHash(
       GURL("http://" + dictionary_domain_2 + "/random_url"),
-      &dictionary);
-  EXPECT_TRUE(dictionary.get());
+      server_hash_2, &problem_code);
+  EXPECT_TRUE(dict_set);
+  EXPECT_TRUE(dict_set->GetDictionary(server_hash_2));
+  EXPECT_EQ(SDCH_OK, problem_code);
 
-  EXPECT_EQ(
-      SDCH_DICTIONARY_HASH_NOT_FOUND,
-      sdch_manager()->GetVcdiffDictionary(
-          server_hash_2, GURL("http://" + dictionary_domain_2 + "/random_url"),
-          &dictionary));
-  EXPECT_FALSE(dictionary.get());
+  dict_set = sdch_manager()->GetDictionarySetByHash(
+      GURL("http://" + dictionary_domain_2 + "/random_url"),
+      server_hash_2, &problem_code);
+  EXPECT_FALSE(dict_set);
+  EXPECT_EQ(SDCH_DICTIONARY_HASH_NOT_FOUND, problem_code);
 
-  EXPECT_EQ(
-      SDCH_DICTIONARY_HASH_NOT_FOUND,
-      second_manager.GetVcdiffDictionary(
-          server_hash_1, GURL("http://" + dictionary_domain_1 + "/random_url"),
-          &dictionary));
-  EXPECT_FALSE(dictionary.get());
+  dict_set = second_manager.GetDictionarySetByHash(
+      GURL("http://" + dictionary_domain_1 + "/random_url"),
+      server_hash_1, &problem_code);
+  EXPECT_FALSE(dict_set);
+  EXPECT_EQ(SDCH_DICTIONARY_HASH_NOT_FOUND, problem_code);
 }
 
 TEST_F(SdchManagerTest, HttpsCorrectlySupported) {
@@ -578,12 +575,16 @@
 
   EXPECT_TRUE(AddSdchDictionary(dictionary_text,
                                 GURL("http://" + dictionary_domain)));
-  scoped_refptr<SdchManager::Dictionary> dictionary;
-  EXPECT_EQ(SDCH_OK, sdch_manager()->GetVcdiffDictionary(
-                         server_hash,
-                         GURL("http://" + dictionary_domain + "/random_url"),
-                         &dictionary));
-  EXPECT_TRUE(dictionary.get());
+
+  scoped_ptr<SdchManager::DictionarySet> dict_set;
+
+  SdchProblemCode problem_code;
+  dict_set = sdch_manager()->GetDictionarySetByHash(
+      GURL("http://" + dictionary_domain + "/random_url"),
+      server_hash, &problem_code);
+  EXPECT_TRUE(dict_set);
+  EXPECT_TRUE(dict_set->GetDictionary(server_hash));
+  EXPECT_EQ(SDCH_OK, problem_code);
 
   sdch_manager()->BlacklistDomain(GURL(blacklist_url), SDCH_OK);
   EXPECT_EQ(SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET,
@@ -591,13 +592,11 @@
 
   sdch_manager()->ClearData();
 
-  dictionary = NULL;
-  EXPECT_EQ(
-      SDCH_DICTIONARY_HASH_NOT_FOUND,
-      sdch_manager()->GetVcdiffDictionary(
-          server_hash, GURL("http://" + dictionary_domain + "/random_url"),
-          &dictionary));
-  EXPECT_FALSE(dictionary.get());
+  dict_set = sdch_manager()->GetDictionarySetByHash(
+      GURL("http://" + dictionary_domain + "/random_url"),
+      server_hash, &problem_code);
+  EXPECT_FALSE(dict_set);
+  EXPECT_EQ(SDCH_DICTIONARY_HASH_NOT_FOUND, problem_code);
   EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(blacklist_url));
 }
 
@@ -620,4 +619,39 @@
   EXPECT_EQ(test_dictionary_gurl, observer.last_dictionary_url());
 }
 
+TEST_F(SdchManagerTest, ExpirationCheckedProperly) {
+  // Create an SDCH dictionary with an expiration time in the past.
+  std::string dictionary_domain("x.y.z.google.com");
+  std::string dictionary_text(base::StringPrintf(
+      "Domain: %s\nMax-age: 0\n\n", dictionary_domain.c_str()));
+  dictionary_text.append(
+      kTestVcdiffDictionary, sizeof(kTestVcdiffDictionary) - 1);
+  std::string client_hash;
+  std::string server_hash;
+  SdchManager::GenerateHash(dictionary_text, &client_hash, &server_hash);
+  GURL target_gurl("http://" + dictionary_domain);
+  AddSdchDictionary(dictionary_text, target_gurl);
+
+  // It should be visible if looked up by hash whether expired or not.
+  scoped_ptr<base::SimpleTestClock> clock(new base::SimpleTestClock);
+  clock->SetNow(base::Time::Now());
+  clock->Advance(base::TimeDelta::FromMinutes(5));
+  SdchProblemCode problem_code;
+  scoped_ptr<SdchManager::DictionarySet> hash_set(
+      sdch_manager()->GetDictionarySetByHash(
+          target_gurl, server_hash, &problem_code).Pass());
+  ASSERT_TRUE(hash_set);
+  ASSERT_EQ(SDCH_OK, problem_code);
+  const_cast<SdchManager::Dictionary*>(
+      hash_set->GetDictionary(server_hash))->SetClockForTesting(
+      clock.Pass());
+
+  // Make sure it's not visible for advertisement, but is visible
+  // if looked up by hash.
+  EXPECT_FALSE(sdch_manager()->GetDictionarySet(target_gurl));
+  EXPECT_TRUE(sdch_manager()->GetDictionarySetByHash(
+      target_gurl, server_hash, &problem_code));
+  EXPECT_EQ(SDCH_OK, problem_code);
+}
+
 }  // namespace net
diff --git a/net/base/sdch_problem_code_list.h b/net/base/sdch_problem_code_list.h
index a0d5196..0eef912 100644
--- a/net/base/sdch_problem_code_list.h
+++ b/net/base/sdch_problem_code_list.h
@@ -65,6 +65,10 @@
 SDCH_PROBLEM_CODE(MULTIENCODING_FOR_NON_SDCH_REQUEST, 50)
 SDCH_PROBLEM_CODE(SDCH_CONTENT_ENCODE_FOR_NON_SDCH_REQUEST, 51)
 
+// A dictionary that wasn't advertised is being used for decoding.
+SDCH_PROBLEM_CODE(UNADVERTISED_DICTIONARY_USED, 52)
+SDCH_PROBLEM_CODE(UNADVERTISED_DICTIONARY_USED_CACHED, 53)
+
 // Dictionary manager issues.
 SDCH_PROBLEM_CODE(DOMAIN_BLACKLIST_INCLUDES_TARGET, 61)
 
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc
index c3f118d..cd9c9b8 100644
--- a/net/cookies/cookie_monster.cc
+++ b/net/cookies/cookie_monster.cc
@@ -1319,16 +1319,12 @@
   if (!HasCookieableScheme(url))
     return std::string();
 
-  TimeTicks start_time(TimeTicks::Now());
-
   std::vector<CanonicalCookie*> cookies;
   FindCookiesForHostAndDomain(url, options, true, &cookies);
   std::sort(cookies.begin(), cookies.end(), CookieSorter);
 
   std::string cookie_line = BuildCookieLine(cookies);
 
-  histogram_time_get_->AddTime(TimeTicks::Now() - start_time);
-
   VLOG(kVlogGetCookies) << "GetCookies() result: " << cookie_line;
 
   return cookie_line;
@@ -2245,9 +2241,6 @@
       base::Histogram::kUmaTargetedHistogramFlag);
 
   // From UMA_HISTOGRAM_{CUSTOM_,}TIMES
-  histogram_time_get_ = base::Histogram::FactoryTimeGet("Cookie.TimeGet",
-      base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(1),
-      50, base::Histogram::kUmaTargetedHistogramFlag);
   histogram_time_blocked_on_load_ = base::Histogram::FactoryTimeGet(
       "Cookie.TimeBlockedOnLoad",
       base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(1),
diff --git a/net/cookies/cookie_monster.h b/net/cookies/cookie_monster.h
index 18d1b8a..0f00490 100644
--- a/net/cookies/cookie_monster.h
+++ b/net/cookies/cookie_monster.h
@@ -635,7 +635,6 @@
   base::HistogramBase* histogram_domain_per_etldp1_count_;
   base::HistogramBase* histogram_number_duplicate_db_cookies_;
   base::HistogramBase* histogram_cookie_deletion_cause_;
-  base::HistogramBase* histogram_time_get_;
   base::HistogramBase* histogram_time_mac_;
   base::HistogramBase* histogram_time_blocked_on_load_;
 
diff --git a/net/disk_cache/blockfile/in_flight_backend_io.cc b/net/disk_cache/blockfile/in_flight_backend_io.cc
index 2cb3ff0..5b3b904 100644
--- a/net/disk_cache/blockfile/in_flight_backend_io.cc
+++ b/net/disk_cache/blockfile/in_flight_backend_io.cc
@@ -341,35 +341,57 @@
 }
 
 void InFlightBackendIO::Init(const net::CompletionCallback& callback) {
-  scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback));
+  // TODO(vadimt): Remove wrapping the callback with
+  // ScopedTracker::TrackCallback() once crbug.com/422516 is fixed.
+  scoped_refptr<BackendIO> operation(new BackendIO(
+      this, backend_,
+      tracked_objects::ScopedTracker::TrackCallback(
+          FROM_HERE_WITH_EXPLICIT_FUNCTION("422516 InFlightBackendIO::Init"),
+          callback)));
   operation->Init();
   PostOperation(operation.get());
 }
 
 void InFlightBackendIO::OpenEntry(const std::string& key, Entry** entry,
                                   const net::CompletionCallback& callback) {
-  scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback));
+  scoped_refptr<BackendIO> operation(new BackendIO(
+      this, backend_, tracked_objects::ScopedTracker::TrackCallback(
+                          FROM_HERE_WITH_EXPLICIT_FUNCTION(
+                              "422516 InFlightBackendIO::OpenEntry"),
+                          callback)));
   operation->OpenEntry(key, entry);
   PostOperation(operation.get());
 }
 
 void InFlightBackendIO::CreateEntry(const std::string& key, Entry** entry,
                                     const net::CompletionCallback& callback) {
-  scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback));
+  scoped_refptr<BackendIO> operation(new BackendIO(
+      this, backend_, tracked_objects::ScopedTracker::TrackCallback(
+                          FROM_HERE_WITH_EXPLICIT_FUNCTION(
+                              "422516 InFlightBackendIO::CreateEntry"),
+                          callback)));
   operation->CreateEntry(key, entry);
   PostOperation(operation.get());
 }
 
 void InFlightBackendIO::DoomEntry(const std::string& key,
                                   const net::CompletionCallback& callback) {
-  scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback));
+  scoped_refptr<BackendIO> operation(new BackendIO(
+      this, backend_, tracked_objects::ScopedTracker::TrackCallback(
+                          FROM_HERE_WITH_EXPLICIT_FUNCTION(
+                              "422516 InFlightBackendIO::DoomEntry"),
+                          callback)));
   operation->DoomEntry(key);
   PostOperation(operation.get());
 }
 
 void InFlightBackendIO::DoomAllEntries(
     const net::CompletionCallback& callback) {
-  scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback));
+  scoped_refptr<BackendIO> operation(new BackendIO(
+      this, backend_, tracked_objects::ScopedTracker::TrackCallback(
+                          FROM_HERE_WITH_EXPLICIT_FUNCTION(
+                              "422516 InFlightBackendIO::DoomAllEntries"),
+                          callback)));
   operation->DoomAllEntries();
   PostOperation(operation.get());
 }
@@ -377,14 +399,22 @@
 void InFlightBackendIO::DoomEntriesBetween(const base::Time initial_time,
                         const base::Time end_time,
                         const net::CompletionCallback& callback) {
-  scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback));
+  scoped_refptr<BackendIO> operation(new BackendIO(
+      this, backend_, tracked_objects::ScopedTracker::TrackCallback(
+                          FROM_HERE_WITH_EXPLICIT_FUNCTION(
+                              "422516 InFlightBackendIO::DoomEntriesBetween"),
+                          callback)));
   operation->DoomEntriesBetween(initial_time, end_time);
   PostOperation(operation.get());
 }
 
 void InFlightBackendIO::DoomEntriesSince(
     const base::Time initial_time, const net::CompletionCallback& callback) {
-  scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback));
+  scoped_refptr<BackendIO> operation(new BackendIO(
+      this, backend_, tracked_objects::ScopedTracker::TrackCallback(
+                          FROM_HERE_WITH_EXPLICIT_FUNCTION(
+                              "422516 InFlightBackendIO::DoomEntriesSince"),
+                          callback)));
   operation->DoomEntriesSince(initial_time);
   PostOperation(operation.get());
 }
@@ -392,7 +422,11 @@
 void InFlightBackendIO::OpenNextEntry(Rankings::Iterator* iterator,
                                       Entry** next_entry,
                                       const net::CompletionCallback& callback) {
-  scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback));
+  scoped_refptr<BackendIO> operation(new BackendIO(
+      this, backend_, tracked_objects::ScopedTracker::TrackCallback(
+                          FROM_HERE_WITH_EXPLICIT_FUNCTION(
+                              "422516 InFlightBackendIO::OpenNextEntry"),
+                          callback)));
   operation->OpenNextEntry(iterator, next_entry);
   PostOperation(operation.get());
 }
@@ -427,14 +461,22 @@
 }
 
 void InFlightBackendIO::FlushQueue(const net::CompletionCallback& callback) {
-  scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback));
+  scoped_refptr<BackendIO> operation(new BackendIO(
+      this, backend_, tracked_objects::ScopedTracker::TrackCallback(
+                          FROM_HERE_WITH_EXPLICIT_FUNCTION(
+                              "422516 InFlightBackendIO::FlushQueue"),
+                          callback)));
   operation->FlushQueue();
   PostOperation(operation.get());
 }
 
 void InFlightBackendIO::RunTask(
     const base::Closure& task, const net::CompletionCallback& callback) {
-  scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback));
+  scoped_refptr<BackendIO> operation(new BackendIO(
+      this, backend_,
+      tracked_objects::ScopedTracker::TrackCallback(
+          FROM_HERE_WITH_EXPLICIT_FUNCTION("422516 InFlightBackendIO::RunTask"),
+          callback)));
   operation->RunTask(task);
   PostOperation(operation.get());
 }
@@ -442,7 +484,11 @@
 void InFlightBackendIO::ReadData(EntryImpl* entry, int index, int offset,
                                  net::IOBuffer* buf, int buf_len,
                                  const net::CompletionCallback& callback) {
-  scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback));
+  scoped_refptr<BackendIO> operation(new BackendIO(
+      this, backend_, tracked_objects::ScopedTracker::TrackCallback(
+                          FROM_HERE_WITH_EXPLICIT_FUNCTION(
+                              "422516 InFlightBackendIO::ReadData"),
+                          callback)));
   operation->ReadData(entry, index, offset, buf, buf_len);
   PostOperation(operation.get());
 }
@@ -451,7 +497,11 @@
                                   net::IOBuffer* buf, int buf_len,
                                   bool truncate,
                                   const net::CompletionCallback& callback) {
-  scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback));
+  scoped_refptr<BackendIO> operation(new BackendIO(
+      this, backend_, tracked_objects::ScopedTracker::TrackCallback(
+                          FROM_HERE_WITH_EXPLICIT_FUNCTION(
+                              "422516 InFlightBackendIO::WriteData"),
+                          callback)));
   operation->WriteData(entry, index, offset, buf, buf_len, truncate);
   PostOperation(operation.get());
 }
@@ -459,7 +509,11 @@
 void InFlightBackendIO::ReadSparseData(
     EntryImpl* entry, int64 offset, net::IOBuffer* buf, int buf_len,
     const net::CompletionCallback& callback) {
-  scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback));
+  scoped_refptr<BackendIO> operation(new BackendIO(
+      this, backend_, tracked_objects::ScopedTracker::TrackCallback(
+                          FROM_HERE_WITH_EXPLICIT_FUNCTION(
+                              "422516 InFlightBackendIO::ReadSparseData"),
+                          callback)));
   operation->ReadSparseData(entry, offset, buf, buf_len);
   PostOperation(operation.get());
 }
@@ -467,7 +521,11 @@
 void InFlightBackendIO::WriteSparseData(
     EntryImpl* entry, int64 offset, net::IOBuffer* buf, int buf_len,
     const net::CompletionCallback& callback) {
-  scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback));
+  scoped_refptr<BackendIO> operation(new BackendIO(
+      this, backend_, tracked_objects::ScopedTracker::TrackCallback(
+                          FROM_HERE_WITH_EXPLICIT_FUNCTION(
+                              "422516 InFlightBackendIO::WriteSparseData"),
+                          callback)));
   operation->WriteSparseData(entry, offset, buf, buf_len);
   PostOperation(operation.get());
 }
@@ -475,7 +533,11 @@
 void InFlightBackendIO::GetAvailableRange(
     EntryImpl* entry, int64 offset, int len, int64* start,
     const net::CompletionCallback& callback) {
-  scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback));
+  scoped_refptr<BackendIO> operation(new BackendIO(
+      this, backend_, tracked_objects::ScopedTracker::TrackCallback(
+                          FROM_HERE_WITH_EXPLICIT_FUNCTION(
+                              "422516 InFlightBackendIO::GetAvailableRange"),
+                          callback)));
   operation->GetAvailableRange(entry, offset, len, start);
   PostOperation(operation.get());
 }
@@ -489,7 +551,11 @@
 
 void InFlightBackendIO::ReadyForSparseIO(
     EntryImpl* entry, const net::CompletionCallback& callback) {
-  scoped_refptr<BackendIO> operation(new BackendIO(this, backend_, callback));
+  scoped_refptr<BackendIO> operation(new BackendIO(
+      this, backend_, tracked_objects::ScopedTracker::TrackCallback(
+                          FROM_HERE_WITH_EXPLICIT_FUNCTION(
+                              "422516 InFlightBackendIO::CancelSparseIO"),
+                          callback)));
   operation->ReadyForSparseIO(entry);
   PostOperation(operation.get());
 }
diff --git a/net/disk_cache/simple/simple_util_win.cc b/net/disk_cache/simple/simple_util_win.cc
index d0d191d..f2adcd0 100644
--- a/net/disk_cache/simple/simple_util_win.cc
+++ b/net/disk_cache/simple/simple_util_win.cc
@@ -24,7 +24,7 @@
   // Why a random name? Because if the name was derived from our original name,
   // then churn on a particular cache entry could cause flakey behaviour.
 
-  // TODO(gaivnp): Ensure these "todelete_" files are cleaned up on periodic
+  // TODO(gavinp): Ensure these "todelete_" files are cleaned up on periodic
   // directory sweeps.
   const base::FilePath rename_target =
       path.DirName().AppendASCII(base::StringPrintf("todelete_%016" PRIx64,
diff --git a/net/dns/dns_config_service_win_unittest.cc b/net/dns/dns_config_service_win_unittest.cc
index 7ac01d1..54a6411 100644
--- a/net/dns/dns_config_service_win_unittest.cc
+++ b/net/dns/dns_config_service_win_unittest.cc
@@ -55,7 +55,7 @@
   IF_OPER_STATUS oper_status;
   const WCHAR* dns_suffix;
   std::string dns_server_addresses[4];  // Empty string indicates end.
-  int ports[4];
+  uint16 ports[4];
 };
 
 scoped_ptr<IP_ADAPTER_ADDRESSES, base::FreeDeleter> CreateAdapterAddresses(
@@ -102,7 +102,7 @@
       }
       IPAddressNumber ip;
       CHECK(ParseIPLiteralToNumber(info.dns_server_addresses[j], &ip));
-      IPEndPoint ipe(ip, info.ports[j]);
+      IPEndPoint ipe = IPEndPoint(ip, info.ports[j]);
       address->Address.lpSockaddr =
           reinterpret_cast<LPSOCKADDR>(storage + num_addresses);
       socklen_t length = sizeof(struct sockaddr_storage);
@@ -120,7 +120,7 @@
     AdapterInfo input_adapters[4];        // |if_type| == 0 indicates end.
     std::string expected_nameservers[4];  // Empty string indicates end.
     std::string expected_suffix;
-    int expected_ports[4];
+    uint16 expected_ports[4];
   } cases[] = {
     {  // Ignore loopback and inactive adapters.
       {
@@ -181,7 +181,7 @@
     for (size_t j = 0; !t.expected_nameservers[j].empty(); ++j) {
       IPAddressNumber ip;
       ASSERT_TRUE(ParseIPLiteralToNumber(t.expected_nameservers[j], &ip));
-      int port = t.expected_ports[j];
+      uint16 port = t.expected_ports[j];
       if (!port)
         port = dns_protocol::kDefaultPort;
       expected_nameservers.push_back(IPEndPoint(ip, port));
diff --git a/net/dns/host_resolver.h b/net/dns/host_resolver.h
index 2823c4b..0203dc9 100644
--- a/net/dns/host_resolver.h
+++ b/net/dns/host_resolver.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
 #include "net/base/address_family.h"
 #include "net/base/completion_callback.h"
@@ -67,7 +68,7 @@
       host_port_pair_ = host_port_pair;
     }
 
-    int port() const { return host_port_pair_.port(); }
+    uint16 port() const { return host_port_pair_.port(); }
     const std::string& hostname() const { return host_port_pair_.host(); }
 
     AddressFamily address_family() const { return address_family_; }
diff --git a/net/dns/host_resolver_impl.cc b/net/dns/host_resolver_impl.cc
index fe63820..9426da5 100644
--- a/net/dns/host_resolver_impl.cc
+++ b/net/dns/host_resolver_impl.cc
@@ -300,14 +300,13 @@
 #elif defined(OS_WIN)
     // Map the error code to a human-readable string.
     LPWSTR error_string = NULL;
-    int size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
-                             FORMAT_MESSAGE_FROM_SYSTEM,
-                             0,  // Use the internal message table.
-                             os_error,
-                             0,  // Use default language.
-                             (LPWSTR)&error_string,
-                             0,  // Buffer size.
-                             0);  // Arguments (unused).
+    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+                  0,  // Use the internal message table.
+                  os_error,
+                  0,  // Use default language.
+                  (LPWSTR)&error_string,
+                  0,  // Buffer size.
+                  0);  // Arguments (unused).
     dict->SetString("os_error_string", base::WideToUTF8(error_string));
     LocalFree(error_string);
 #endif
diff --git a/net/dns/host_resolver_impl_unittest.cc b/net/dns/host_resolver_impl_unittest.cc
index 7b6a391..7a46a1c 100644
--- a/net/dns/host_resolver_impl_unittest.cc
+++ b/net/dns/host_resolver_impl_unittest.cc
@@ -181,7 +181,7 @@
 };
 
 bool AddressListContains(const AddressList& list, const std::string& address,
-                         int port) {
+                         uint16 port) {
   IPAddressNumber ip;
   bool rv = ParseIPLiteralToNumber(address, &ip);
   DCHECK(rv);
@@ -249,7 +249,7 @@
   bool completed() const { return result_ != ERR_IO_PENDING; }
   bool pending() const { return handle_ != NULL; }
 
-  bool HasAddress(const std::string& address, int port) const {
+  bool HasAddress(const std::string& address, uint16 port) const {
     return AddressListContains(list_, address, port);
   }
 
@@ -258,7 +258,7 @@
     return list_.size();
   }
 
-  bool HasOneAddress(const std::string& address, int port) const {
+  bool HasOneAddress(const std::string& address, uint16 port) const {
     return HasAddress(address, port) && (NumberOfAddresses() == 1u);
   }
 
diff --git a/net/dns/mock_host_resolver.cc b/net/dns/mock_host_resolver.cc
index 48e004e..6d8cba3 100644
--- a/net/dns/mock_host_resolver.cc
+++ b/net/dns/mock_host_resolver.cc
@@ -48,7 +48,7 @@
       LOG(WARNING) << "Not a supported IP literal: " << addresses[index];
       return ERR_UNEXPECTED;
     }
-    addrlist->push_back(IPEndPoint(ip_number, -1));
+    addrlist->push_back(IPEndPoint(ip_number, 0));
   }
   return OK;
 }
diff --git a/net/filter/filter.cc b/net/filter/filter.cc
index 53d6583..b3f98cb 100644
--- a/net/filter/filter.cc
+++ b/net/filter/filter.cc
@@ -3,20 +3,20 @@
 // found in the LICENSE file.
 
 // The basic usage of the Filter interface is described in the comment at
-// the beginning of filter.h.  If Filter::Factory is passed a vector of
+// the beginning of filter.h. If Filter::Factory is passed a vector of
 // size greater than 1, that interface is implemented by a series of filters
-// connected in a chain.  In such a case the first filter
+// connected in a chain. In such a case the first filter
 // in the chain proxies calls to ReadData() so that its return values
 // apply to the entire chain.
 //
 // In a filter chain, the data flows from first filter (held by the
-// caller) down the chain.  When ReadData() is called on any filter
+// caller) down the chain. When ReadData() is called on any filter
 // except for the last filter, it proxies the call down the chain,
 // filling in the input buffers of subsequent filters if needed (==
 // that filter's last_status() value is FILTER_NEED_MORE_DATA) and
-// available (== the current filter has data it can output).  The last
+// available (== the current filter has data it can output). The last
 // Filter will then output data if possible, and return
-// FILTER_NEED_MORE_DATA if not.  Because the indirection pushes
+// FILTER_NEED_MORE_DATA if not. Because the indirection pushes
 // data along the filter chain at each level if it's available and the
 // next filter needs it, a return value of FILTER_NEED_MORE_DATA from the
 // final filter will apply to the entire chain.
@@ -43,8 +43,8 @@
 const char kGZip[]         = "gzip";
 const char kXGZip[]        = "x-gzip";
 const char kSdch[]         = "sdch";
-// compress and x-compress are currently not supported.  If we decide to support
-// them, we'll need the same mime type compatibility hack we have for gzip.  For
+// compress and x-compress are currently not supported. If we decide to support
+// them, we'll need the same mime type compatibility hack we have for gzip. For
 // more information, see Firefox's nsHttpChannel::ProcessNormal.
 
 // Mime types:
@@ -153,9 +153,9 @@
     // In the case where this filter has data internally, and is indicating such
     // with a last_status_ of FILTER_OK, but at the same time the next filter in
     // the chain indicated it FILTER_NEED_MORE_DATA, we have to be cautious
-    // about confusing the caller.  The API confusion can appear if we return
+    // about confusing the caller. The API confusion can appear if we return
     // FILTER_OK (suggesting we have more data in aggregate), but yet we don't
-    // populate our output buffer.  When that is the case, we need to
+    // populate our output buffer. When that is the case, we need to
     // alternately call our filter element, and the next_filter element until we
     // get out of this state (by pumping data into the next filter until it
     // outputs data, or it runs out of data and reports that it NEED_MORE_DATA.)
@@ -217,8 +217,8 @@
         LowerCaseEqualsASCII(mime_type, kApplicationGzip) ||
         LowerCaseEqualsASCII(mime_type, kApplicationXGunzip))
       // The server has told us that it sent us gziped content with a gzip
-      // content encoding.  Sadly, Apache mistakenly sets these headers for all
-      // .gz files.  We match Firefox's nsHttpChannel::ProcessNormal and ignore
+      // content encoding. Sadly, Apache mistakenly sets these headers for all
+      // .gz files. We match Firefox's nsHttpChannel::ProcessNormal and ignore
       // the Content-Encoding here.
       encoding_types->clear();
 
@@ -256,7 +256,7 @@
   }
 
   // If the request was for SDCH content, then we might need additional fixups.
-  if (!filter_context.SdchResponseExpected()) {
+  if (!filter_context.SdchDictionariesAdvertised()) {
     // It was not an SDCH request, so we'll just record stats.
     if (1 < encoding_types->size()) {
       // Multiple filters were intended to only be used for SDCH (thus far!)
@@ -271,7 +271,7 @@
   }
 
   // The request was tagged as an SDCH request, which means the server supplied
-  // a dictionary, and we advertised it in the request.  Some proxies will do
+  // a dictionary, and we advertised it in the request. Some proxies will do
   // very strange things to the request, or the response, so we have to handle
   // them gracefully.
 
@@ -280,7 +280,7 @@
       (FILTER_TYPE_SDCH == encoding_types->front())) {
     // Some proxies (found currently in Argentina) strip the Content-Encoding
     // text from "sdch,gzip" to a mere "sdch" without modifying the compressed
-    // payload.   To handle this gracefully, we simulate the "probably" deleted
+    // payload.  To handle this gracefully, we simulate the "probably" deleted
     // ",gzip" by appending a tentative gzip decode, which will default to a
     // no-op pass through filter if it doesn't get gzip headers where expected.
     if (1 == encoding_types->size()) {
@@ -290,20 +290,20 @@
     return;
   }
 
-  // There are now several cases to handle for an SDCH request.  Foremost, if
+  // There are now several cases to handle for an SDCH request. Foremost, if
   // the outbound request was stripped so as not to advertise support for
   // encodings, we might get back content with no encoding, or (for example)
-  // just gzip.  We have to be sure that any changes we make allow for such
-  // minimal coding to work.  That issue is why we use TENTATIVE filters if we
+  // just gzip. We have to be sure that any changes we make allow for such
+  // minimal coding to work. That issue is why we use TENTATIVE filters if we
   // add any, as those filters sniff the content, and act as pass-through
   // filters if headers are not found.
 
   // If the outbound GET is not modified, then the server will generally try to
-  // send us SDCH encoded content.  As that content returns, there are several
+  // send us SDCH encoded content. As that content returns, there are several
   // corruptions of the header "content-encoding" that proxies may perform (and
-  // have been detected in the wild).  We already dealt with the a honest
+  // have been detected in the wild). We already dealt with the a honest
   // content encoding of "sdch,gzip" being corrupted into "sdch" with on change
-  // of the actual content.  Another common corruption is to either disscard
+  // of the actual content. Another common corruption is to either disscard
   // the accurate content encoding, or to replace it with gzip only (again, with
   // no change in actual content). The last observed corruption it to actually
   // change the content, such as by re-gzipping it, and that may happen along
@@ -328,7 +328,7 @@
   } else {
     // Remarkable case!?!  We advertised an SDCH dictionary, content-encoding
     // was not marked for SDCH processing: Why did the server suggest an SDCH
-    // dictionary in the first place??.  Also, the content isn't
+    // dictionary in the first place??. Also, the content isn't
     // tagged as HTML, despite the fact that SDCH encoding is mostly likely for
     // HTML: Did some anti-virus system strip this tag (sometimes they strip
     // accept-encoding headers on the request)??  Does the content encoding not
@@ -344,9 +344,9 @@
   }
 
   // Leave the existing encoding type to be processed first, and add our
-  // tentative decodings to be done afterwards.  Vodaphone UK reportedyl will
+  // tentative decodings to be done afterwards. Vodaphone UK reportedyl will
   // perform a second layer of gzip encoding atop the server's sdch,gzip
-  // encoding, and then claim that the content encoding is a mere gzip.  As a
+  // encoding, and then claim that the content encoding is a mere gzip. As a
   // result we'll need (in that case) to do the gunzip, plus our tentative
   // gunzip and tentative SDCH decoding.
   // This approach nicely handles the empty() list as well, and should work with
diff --git a/net/filter/filter.h b/net/filter/filter.h
index cec8398..428dc8c 100644
--- a/net/filter/filter.h
+++ b/net/filter/filter.h
@@ -20,22 +20,22 @@
 // through its accessor and fills in stream_buffer_ with pre-filter data, next
 // calls FlushStreamBuffer to notify Filter, then calls ReadFilteredData
 // repeatedly to get all the filtered data. After all data have been filtered
-// and read out, the caller may fill in stream_buffer_ again.  This
+// and read out, the caller may fill in stream_buffer_ again. This
 // WriteBuffer-Flush-Read cycle is repeated until reaching the end of data
 // stream.
 //
 // A return of FILTER_OK from ReadData() means that more data is
 // available to a future ReadData() call and data may not be written
-// into stream_buffer().  A return of FILTER_NEED_MORE_DATA from ReadData()
+// into stream_buffer(). A return of FILTER_NEED_MORE_DATA from ReadData()
 // indicates that no data will be forthcoming from the filter until
 // it receives more input data, and that the buffer at
 // stream_buffer() may be written to.
 //
 // The filter being complete (no more data to provide) may be indicated
 // by either returning FILTER_DONE or by returning FILTER_OK and indicating
-// zero bytes output; consumers understand both those signals.  Consumers
+// zero bytes output; consumers understand both those signals. Consumers
 // are responsible for not calling ReadData() on a filter after one of these
-// signals have been returned.  Note that some filters may never signal that
+// signals have been returned. Note that some filters may never signal that
 // they are done (e.g. a pass-through filter will always
 // say FILTER_NEED_MORE_DATA), so the consumer will also need to
 // recognize the state of |no_more_input_data_available &&
@@ -55,6 +55,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/time/time.h"
 #include "net/base/net_export.h"
+#include "net/base/sdch_manager.h"
 
 class GURL;
 
@@ -66,11 +67,19 @@
 
 //------------------------------------------------------------------------------
 // Define an interface class that allows access to contextual information
-// supplied by the owner of this filter.  In the case where there are a chain of
+// supplied by the owner of this filter. In the case where there are a chain of
 // filters, there is only one owner of all the chained filters, and that context
-// is passed to the constructor of all those filters.  To be clear, the context
+// is passed to the constructor of all those filters. To be clear, the context
 // does NOT reflect the position in a chain, or the fact that there are prior
 // or later filters in a chain.
+//
+// TODO(rdsmith): FilterContext is a grab-bag of methods which may or may
+// not be relevant for any particular filter, and it's getting worse over
+// time. In addition, it only supports two filters, SDCH and gzip.
+// It would make more sense to implement FilterContext as a
+// base::SupportsUserData structure to which filter-specific information
+// could be added by whatever the ultimate consumer of the filter chain is,
+// and a particular filter (if included) could access that information.
 class NET_EXPORT_PRIVATE FilterContext {
  public:
   // Enum to control what histograms are emitted near end-of-life of this
@@ -107,14 +116,14 @@
   virtual bool IsDownload() const = 0;
 
   // Was this data flagged as a response to a request with an SDCH dictionary?
-  virtual bool SdchResponseExpected() const = 0;
+  virtual SdchManager::DictionarySet* SdchDictionariesAdvertised() const = 0;
 
   // How many bytes were read from the net or cache so far (and potentially
   // pushed into a filter for processing)?
   virtual int64 GetByteReadCount() const = 0;
 
   // What response code was received with the associated network transaction?
-  // For example: 200 is ok.   4xx are error codes. etc.
+  // For example: 200 is ok.  4xx are error codes. etc.
   virtual int GetResponseCode() const = 0;
 
   // The URLRequestContext associated with the request.
@@ -137,7 +146,7 @@
     FILTER_OK,
     // Read filtered data successfully, and the data in the buffer has been
     // consumed by the filter, but more data is needed in order to continue
-    // filtering.  At this point, the caller is free to reuse the filter
+    // filtering. At this point, the caller is free to reuse the filter
     // buffer to provide more data.
     FILTER_NEED_MORE_DATA,
     // Read filtered data successfully, and filter reaches the end of the data
@@ -169,7 +178,7 @@
   //
   // Note: filter_types is an array of filter types (content encoding types as
   // provided in an HTTP header), which will be chained together serially to do
-  // successive filtering of data.  The types in the vector are ordered based on
+  // successive filtering of data. The types in the vector are ordered based on
   // encoding order, and the filters are chained to operate in the reverse
   // (decoding) order. For example, types[0] = FILTER_TYPE_SDCH,
   // types[1] = FILTER_TYPE_GZIP will cause data to first be gunzip filtered,
@@ -182,7 +191,7 @@
   // initialized.
   static Filter* GZipFactory();
 
-  // External call to obtain data from this filter chain.  If ther is no
+  // External call to obtain data from this filter chain. If ther is no
   // next_filter_, then it obtains data from this specific filter.
   FilterStatus ReadData(char* dest_buffer, int* dest_len);
 
@@ -216,10 +225,10 @@
   static FilterType ConvertEncodingToType(const std::string& filter_type);
 
   // Given a array of encoding_types, try to do some error recovery adjustment
-  // to the list.  This includes handling known bugs in the Apache server (where
+  // to the list. This includes handling known bugs in the Apache server (where
   // redundant gzip encoding is specified), as well as issues regarding SDCH
   // encoding, where various proxies and anti-virus products modify or strip the
-  // encodings.  These fixups require context, which includes whether this
+  // encodings. These fixups require context, which includes whether this
   // response was made to an SDCH request (i.e., an available dictionary was
   // advertised in the GET), as well as the mime type of the content.
   static void FixupEncodingTypes(const FilterContext& filter_context,
@@ -270,8 +279,8 @@
   void InitBuffer(int size);
 
   // A factory helper for creating filters for within a chain of potentially
-  // multiple encodings.  If a chain of filters is created, then this may be
-  // called multiple times during the filter creation process.  In most simple
+  // multiple encodings. If a chain of filters is created, then this may be
+  // called multiple times during the filter creation process. In most simple
   // cases, this is only called once. Returns NULL and cleans up (deleting
   // filter_list) if a new filter can't be constructed.
   static Filter* PrependNewFilter(FilterType type_id,
diff --git a/net/filter/filter_unittest.cc b/net/filter/filter_unittest.cc
index 5b2446c..fcedeaf 100644
--- a/net/filter/filter_unittest.cc
+++ b/net/filter/filter_unittest.cc
@@ -24,9 +24,6 @@
 
 }  // namespace
 
-class FilterTest : public testing::Test {
-};
-
 TEST(FilterTest, ContentTypeId) {
   // Check for basic translation of Content-Encoding, including case variations.
   EXPECT_EQ(Filter::FILTER_TYPE_DEFLATE,
@@ -54,7 +51,7 @@
 // Check various fixups that modify content encoding lists.
 TEST(FilterTest, ApacheGzip) {
   MockFilterContext filter_context;
-  filter_context.SetSdchResponse(false);
+  filter_context.SetSdchResponse(NULL);
 
   // Check that redundant gzip mime type removes only solo gzip encoding.
   const std::string kGzipMime1("application/x-gzip");
@@ -100,7 +97,7 @@
 
 TEST(FilterTest, GzipContentDispositionFilename) {
   MockFilterContext filter_context;
-  filter_context.SetSdchResponse(false);
+  filter_context.SetSdchResponse(NULL);
 
   const std::string kGzipMime("application/x-tar");
   const std::string kContentDisposition("attachment; filename=\"foo.tgz\"");
@@ -119,7 +116,9 @@
   // Handle content encodings including SDCH.
   const std::string kTextHtmlMime("text/html");
   MockFilterContext filter_context;
-  filter_context.SetSdchResponse(true);
+  // Empty handle indicates to filter that SDCH is active.
+  filter_context.SetSdchResponse(
+      SdchManager::CreateEmptyDictionarySetForTesting().Pass());
 
   std::vector<Filter::FilterType> encoding_types;
 
@@ -156,7 +155,8 @@
   // Handle interesting case where entire SDCH encoding assertion "got lost."
   const std::string kTextHtmlMime("text/html");
   MockFilterContext filter_context;
-  filter_context.SetSdchResponse(true);
+  filter_context.SetSdchResponse(
+      SdchManager::CreateEmptyDictionarySetForTesting().Pass());
 
   std::vector<Filter::FilterType> encoding_types;
 
@@ -169,7 +169,7 @@
   EXPECT_EQ(Filter::FILTER_TYPE_GZIP_HELPING_SDCH, encoding_types[1]);
 
   // Loss of encoding, but it was an SDCH response with a prefix that says it
-  // was an html type.  Note that it *should* be the case that a precise match
+  // was an html type. Note that it *should* be the case that a precise match
   // with "text/html" we be collected by GetMimeType() and passed in, but we
   // coded the fixup defensively (scanning for a prefix of "text/html", so this
   // is an example which could survive such confusion in the caller).
diff --git a/net/filter/mock_filter_context.cc b/net/filter/mock_filter_context.cc
index 35ab9ee..67012de 100644
--- a/net/filter/mock_filter_context.cc
+++ b/net/filter/mock_filter_context.cc
@@ -11,7 +11,6 @@
 MockFilterContext::MockFilterContext()
     : is_cached_content_(false),
       is_download_(false),
-      is_sdch_response_(false),
       ok_to_call_get_url_(true),
       response_code_(-1),
       context_(new URLRequestContext()) {
@@ -54,8 +53,9 @@
 
 bool MockFilterContext::IsDownload() const { return is_download_; }
 
-bool MockFilterContext::SdchResponseExpected() const {
-  return is_sdch_response_;
+SdchManager::DictionarySet*
+MockFilterContext::SdchDictionariesAdvertised() const {
+  return dictionaries_handle_.get();
 }
 
 int64 MockFilterContext::GetByteReadCount() const { return 0; }
diff --git a/net/filter/mock_filter_context.h b/net/filter/mock_filter_context.h
index 41c9e9e..776a237 100644
--- a/net/filter/mock_filter_context.h
+++ b/net/filter/mock_filter_context.h
@@ -9,6 +9,7 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "net/base/net_log.h"
+#include "net/base/sdch_manager.h"
 #include "net/filter/filter.h"
 #include "url/gurl.h"
 
@@ -30,15 +31,15 @@
   void SetCached(bool is_cached) { is_cached_content_ = is_cached; }
   void SetDownload(bool is_download) { is_download_ = is_download; }
   void SetResponseCode(int response_code) { response_code_ = response_code; }
-  void SetSdchResponse(bool is_sdch_response) {
-    is_sdch_response_ = is_sdch_response;
+  void SetSdchResponse(scoped_ptr<SdchManager::DictionarySet> handle) {
+    dictionaries_handle_ = handle.Pass();
   }
   URLRequestContext* GetModifiableURLRequestContext() const {
     return context_.get();
   }
 
   // After a URLRequest's destructor is called, some interfaces may become
-  // unstable.  This method is used to signal that state, so we can tag use
+  // unstable. This method is used to signal that state, so we can tag use
   // of those interfaces as coding errors.
   void NukeUnstableInterfaces();
 
@@ -61,8 +62,8 @@
   // Is this a download?
   bool IsDownload() const override;
 
-  // Was this data flagged as a response to a request with an SDCH dictionary?
-  bool SdchResponseExpected() const override;
+  // Handle to dictionaries advertised.
+  SdchManager::DictionarySet* SdchDictionariesAdvertised() const override;
 
   // How many bytes were fed to filter(s) so far?
   int64 GetByteReadCount() const override;
@@ -84,7 +85,7 @@
   base::Time request_time_;
   bool is_cached_content_;
   bool is_download_;
-  bool is_sdch_response_;
+  scoped_ptr<SdchManager::DictionarySet> dictionaries_handle_;
   bool ok_to_call_get_url_;
   int response_code_;
   scoped_ptr<URLRequestContext> context_;
diff --git a/net/filter/sdch_filter.cc b/net/filter/sdch_filter.cc
index d1eb7f4..30392cd 100644
--- a/net/filter/sdch_filter.cc
+++ b/net/filter/sdch_filter.cc
@@ -14,6 +14,7 @@
 #include "base/values.h"
 #include "net/base/sdch_manager.h"
 #include "net/base/sdch_net_log_params.h"
+#include "net/base/sdch_problem_codes.h"
 #include "net/url_request/url_request_context.h"
 
 #include "sdch/open-vcdiff/src/google/vcdecoder.h"
@@ -251,12 +252,12 @@
       // advertisement (so that we are sure we're not hurting anything).
       //
       // Watch out for an error page inserted by the proxy as part of a 40x
-      // error response.  When we see such content molestation, we certainly
+      // error response. When we see such content molestation, we certainly
       // need to fall into the meta-refresh case.
       ResponseCorruptionDetectionCause cause = RESPONSE_NONE;
       if (filter_context_.GetResponseCode() == 404) {
         // We could be more generous, but for now, only a "NOT FOUND" code will
-        // cause a pass through.  All other bad codes will fall into a
+        // cause a pass through. All other bad codes will fall into a
         // meta-refresh.
         LogSdchProblem(SDCH_PASS_THROUGH_404_CODE);
         cause = RESPONSE_404;
@@ -276,13 +277,13 @@
         // error. We were just overly cautious when we added a TENTATIVE_SDCH.
         // We added the sdch coding tag, and it should not have been added.
         // This can happen in server experiments, where the server decides
-        // not to use sdch, even though there is a dictionary.  To be
+        // not to use sdch, even though there is a dictionary. To be
         // conservative, we locally added the tentative sdch (fearing that a
         // proxy stripped it!) and we must now recant (pass through).
         //
         // However.... just to be sure we don't get burned by proxies that
         // re-compress with gzip or other system, we can sniff to see if this
-        // is compressed data etc.  For now, we do nothing, which gets us into
+        // is compressed data etc. For now, we do nothing, which gets us into
         // the meta-refresh result.
         // TODO(jar): Improve robustness by sniffing for valid text that we can
         // actual use re: decoding_status_ = PASS_THROUGH;
@@ -292,8 +293,8 @@
         // The common cause is a restart of the browser, where we try to render
         // cached content that was saved when we had a dictionary.
         cause = RESPONSE_NO_DICTIONARY;
-      } else if (filter_context_.SdchResponseExpected()) {
-        // This is a very corrupt SDCH request response.  We can't decode it.
+      } else if (filter_context_.SdchDictionariesAdvertised()) {
+        // This is a very corrupt SDCH request response. We can't decode it.
         // We'll use a meta-refresh, and get content without asking for SDCH.
         // This will also progressively disable SDCH for this domain.
         cause = RESPONSE_CORRUPT_SDCH;
@@ -377,7 +378,7 @@
 
   if (decoding_status_ != DECODING_IN_PROGRESS) {
     if (META_REFRESH_RECOVERY == decoding_status_) {
-      // Absorb all input data.  We've already output page reload HTML.
+      // Absorb all input data. We've already output page reload HTML.
       next_stream_data_ = NULL;
       stream_data_len_ = 0;
       return FILTER_NEED_MORE_DATA;
@@ -441,25 +442,52 @@
   else
     next_stream_data_ = NULL;
 
-  DCHECK(!dictionary_.get());
+  DCHECK(!dictionary_);
   dictionary_hash_is_plausible_ = true;  // Assume plausible, but check.
 
   SdchProblemCode rv = SDCH_OK;
   if ('\0' == dictionary_hash_[kServerIdLength - 1]) {
-    SdchManager* manager(url_request_context_->sdch_manager());
-    rv = manager->GetVcdiffDictionary(
-        std::string(dictionary_hash_, 0, kServerIdLength - 1), url_,
-        &dictionary_);
-    if (rv == SDCH_DICTIONARY_HASH_NOT_FOUND) {
-      DCHECK(dictionary_hash_.size() == kServerIdLength);
-      // Since dictionary was not found, check to see if hash was even
-      // plausible.
-      for (size_t i = 0; i < kServerIdLength - 1; ++i) {
-        char base64_char = dictionary_hash_[i];
-        if (!isalnum(base64_char) && '-' != base64_char && '_' != base64_char) {
-          rv = SDCH_DICTIONARY_HASH_MALFORMED;
-          dictionary_hash_is_plausible_ = false;
-          break;
+    std::string server_hash(dictionary_hash_, 0, kServerIdLength - 1);
+    SdchManager::DictionarySet* handle =
+        filter_context_.SdchDictionariesAdvertised();
+    if (handle)
+      dictionary_ = handle->GetDictionary(server_hash);
+    if (!dictionary_) {
+      // This is a hack. Naively, the dictionaries available for
+      // decoding should be only the ones advertised. However, there are
+      // cases, specifically resources encoded with old dictionaries living
+      // in the cache, that mean the full set of dictionaries should be made
+      // available for decoding. It's not known how often this happens;
+      // if it happens rarely enough, this code can be removed.
+      //
+      // TODO(rdsmith): Long-term, a better solution is necessary, since
+      // an entry in the cache being encoded with the dictionary doesn't
+      // guarantee that the dictionary is present. That solution probably
+      // involves storing unencoded resources in the cache, but might
+      // involve evicting encoded resources on dictionary removal.
+      // See http://crbug.com/383405.
+      unexpected_dictionary_handle_ =
+          url_request_context_->sdch_manager()->GetDictionarySetByHash(
+              url_, server_hash, &rv);
+      if (unexpected_dictionary_handle_) {
+        dictionary_ = unexpected_dictionary_handle_->GetDictionary(server_hash);
+        // Override SDCH_OK rv; this is still worth logging.
+        rv = (filter_context_.IsCachedContent() ?
+              SDCH_UNADVERTISED_DICTIONARY_USED_CACHED :
+              SDCH_UNADVERTISED_DICTIONARY_USED);
+      } else {
+        // Since dictionary was not found, check to see if hash was
+        // even plausible.
+        DCHECK(dictionary_hash_.size() == kServerIdLength);
+        rv = SDCH_DICTIONARY_HASH_NOT_FOUND;
+        for (size_t i = 0; i < kServerIdLength - 1; ++i) {
+          char base64_char = dictionary_hash_[i];
+          if (!isalnum(base64_char) &&
+              '-' != base64_char && '_' != base64_char) {
+            dictionary_hash_is_plausible_ = false;
+            rv = SDCH_DICTIONARY_HASH_MALFORMED;
+            break;
+          }
         }
       }
     }
@@ -467,12 +495,15 @@
     dictionary_hash_is_plausible_ = false;
     rv = SDCH_DICTIONARY_HASH_MALFORMED;
   }
-  if (rv != SDCH_OK) {
+
+  if (rv != SDCH_OK)
     LogSdchProblem(rv);
+
+  if (!dictionary_) {
     decoding_status_ = DECODING_ERROR;
     return FILTER_ERROR;
   }
-  DCHECK(dictionary_.get());
+
   vcdiff_streaming_decoder_.reset(new open_vcdiff::VCDiffStreamingDecoder);
   vcdiff_streaming_decoder_->SetAllowVcdTarget(false);
   vcdiff_streaming_decoder_->StartDecoding(dictionary_->text().data(),
diff --git a/net/filter/sdch_filter.h b/net/filter/sdch_filter.h
index bc7788c..9541742 100644
--- a/net/filter/sdch_filter.h
+++ b/net/filter/sdch_filter.h
@@ -43,7 +43,7 @@
   FilterStatus ReadFilteredData(char* dest_buffer, int* dest_len) override;
 
  private:
-  // Internal status.  Once we enter an error state, we stop processing data.
+  // Internal status. Once we enter an error state, we stop processing data.
   enum DecodingStatus {
     DECODING_UNINITIALIZED,
     WAITING_FOR_DICTIONARY_SELECTION,
@@ -87,19 +87,19 @@
   // After assembling an entire dictionary hash (the first 9 bytes of the
   // sdch payload, we check to see if it is plausible, meaning it has a null
   // termination, and has 8 characters that are possible in a net-safe base64
-  // encoding.  If the hash is not plausible, then the payload is probably not
+  // encoding. If the hash is not plausible, then the payload is probably not
   // an SDCH encoded bundle, and various error recovery strategies can be
   // attempted.
   bool dictionary_hash_is_plausible_;
 
-  // We hold an in-memory copy of the dictionary during the entire decoding, as
-  // it is used directly by the VC-DIFF decoding system.
-  // That char* data is part of the dictionary_ we hold a reference to.
-  scoped_refptr<SdchManager::Dictionary> dictionary_;
+  // Validity of this pointer is guaranteed by either the FilterContext holding
+  // a containing SdchManager::DictionarySet, or this object holding a
+  // container in |unexpected_dictionary_handle_| below.
+  const SdchManager::Dictionary *dictionary_;
 
   // We keep a copy of the URLRequestContext for use in the destructor, (at
   // which point GetURLRequestContext() will likely return null because of
-  // the disassociation of the URLRequest from the URLRequestJob).  This is
+  // the disassociation of the URLRequest from the URLRequestJob). This is
   // safe because the URLRequestJob (and any filters) are guaranteed to be
   // deleted before the URLRequestContext is destroyed.
   const URLRequestContext* const url_request_context_;
@@ -129,6 +129,11 @@
   // by checking within this mime type (we may do a meta-refresh via html).
   std::string mime_type_;
 
+  // If the response was encoded with a dictionary different than those
+  // advertised (e.g. a cached response using an old dictionary), this
+  // variable preserves that dictionary from deletion during decoding.
+  scoped_ptr<SdchManager::DictionarySet> unexpected_dictionary_handle_;
+
   DISALLOW_COPY_AND_ASSIGN(SdchFilter);
 };
 
diff --git a/net/filter/sdch_filter_unittest.cc b/net/filter/sdch_filter_unittest.cc
index 79b5673..be9790d 100644
--- a/net/filter/sdch_filter_unittest.cc
+++ b/net/filter/sdch_filter_unittest.cc
@@ -10,6 +10,7 @@
 
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/test/simple_test_clock.h"
 #include "net/base/io_buffer.h"
 #include "net/filter/mock_filter_context.h"
 #include "net/filter/sdch_filter.h"
@@ -25,12 +26,12 @@
 // Note an SDCH dictionary has extra meta-data before the VCDIFF dictionary.
 static const char kTestVcdiffDictionary[] = "DictionaryFor"
     "SdchCompression1SdchCompression2SdchCompression3SdchCompression\n";
-// Pre-compression test data.  Note that we pad with a lot of highly gzip
-// compressible content to help to exercise the chaining pipeline.  That is why
+// Pre-compression test data. Note that we pad with a lot of highly gzip
+// compressible content to help to exercise the chaining pipeline. That is why
 // there are a PILE of zeros at the start and end.
 // This will ensure that gzip compressed data can be fed to the chain in one
 // gulp, but (with careful selection of intermediate buffers) that it takes
-// several sdch buffers worth of data to satisfy the sdch filter.  See detailed
+// several sdch buffers worth of data to satisfy the sdch filter. See detailed
 // CHECK() calls in FilterChaining test for specifics.
 static const char kTestData[] = "0000000000000000000000000000000000000000000000"
     "0000000000000000000000000000TestData "
@@ -63,8 +64,8 @@
     url_request_context->set_sdch_manager(sdch_manager_.get());
   }
 
-  // Attempt to add a dictionary to the manager; returns whether or not
-  // the attempt succeeded.
+  // Attempt to add a dictionary to the manager and probe for success or
+  // failure.
   bool AddSdchDictionary(const std::string& dictionary_text,
                          const GURL& gurl) {
     return sdch_manager_->AddSdchDictionary(dictionary_text, gurl) == SDCH_OK;
@@ -72,6 +73,13 @@
 
   MockFilterContext* filter_context() { return filter_context_.get(); }
 
+  // Sets both the GURL and the SDCH response for a filter context.
+  void SetupFilterContextWithGURL(GURL url) {
+    filter_context_->SetURL(url);
+    filter_context_->SetSdchResponse(
+        sdch_manager_->GetDictionarySet(url).Pass());
+  }
+
   std::string NewSdchCompressedData(const std::string dictionary) {
     std::string client_hash;
     std::string server_hash;
@@ -108,11 +116,11 @@
 //------------------------------------------------------------------------------
 // Provide a generic helper function for trying to filter data.
 // This function repeatedly calls the filter to process data, until the entire
-// source is consumed.  The return value from the filter is appended to output.
+// source is consumed. The return value from the filter is appended to output.
 // This allows us to vary input and output block sizes in order to test for edge
 // effects (boundary effects?) during the filtering process.
 // This function provides data to the filter in blocks of no-more-than the
-// specified input_block_length.  It allows the filter to fill no more than
+// specified input_block_length. It allows the filter to fill no more than
 // output_buffer_length in any one call to proccess (a.k.a., Read) data, and
 // concatenates all these little output blocks into the singular output string.
 static bool FilterTestData(const std::string& source,
@@ -159,6 +167,19 @@
   return dictionary;
 }
 
+static std::string NewSdchExpiredDictionary(const std::string& domain) {
+  std::string dictionary;
+  if (!domain.empty()) {
+    dictionary.append("Domain: ");
+    dictionary.append(domain);
+    dictionary.append("\n");
+  }
+  dictionary.append("Max-Age: 0\n");
+  dictionary.append("\n");
+  dictionary.append(kTestVcdiffDictionary, sizeof(kTestVcdiffDictionary) - 1);
+  return dictionary;
+}
+
 //------------------------------------------------------------------------------
 
 TEST_F(SdchFilterTest, EmptyInputOk) {
@@ -197,10 +218,10 @@
   EXPECT_EQ(0, output_bytes_or_buffer_size);
   EXPECT_EQ(Filter::FILTER_NEED_MORE_DATA, status);
 
-  // Partially tear down context.  Anything that goes through request()
+  // Partially tear down context. Anything that goes through request()
   // without checking it for null in the URLRequestJob::HttpFilterContext
-  // implementation is suspect.  Everything that does check it for null should
-  // return null.  This is to test for incorrectly relying on filter_context()
+  // implementation is suspect. Everything that does check it for null should
+  // return null. This is to test for incorrectly relying on filter_context()
   // from the SdchFilter destructor.
   filter_context()->NukeUnstableInterfaces();
 }
@@ -451,7 +472,7 @@
   std::vector<Filter::FilterType> filter_types;
   filter_types.push_back(Filter::FILTER_TYPE_SDCH);
 
-  filter_context()->SetURL(url);
+  SetupFilterContextWithGURL(url);
 
   scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
 
@@ -488,7 +509,8 @@
   std::vector<Filter::FilterType> filter_types;
   filter_types.push_back(Filter::FILTER_TYPE_SDCH);
 
-  filter_context()->SetURL(GURL("https://" + kSampleDomain));
+  GURL filter_context_gurl("https://" + kSampleDomain);
+  SetupFilterContextWithGURL(GURL("https://" + kSampleDomain));
   scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
 
   const size_t feed_block_size(100);
@@ -501,7 +523,7 @@
 
 // Current failsafe TODO/hack refuses to decode any content that doesn't use
 // http as the scheme (see use of DICTIONARY_SELECTED_FOR_NON_HTTP).
-// The following tests this blockage.  Note that blacklisting results, so we
+// The following tests this blockage. Note that blacklisting results, so we
 // we need separate tests for each of these.
 TEST_F(SdchFilterTest, NoDecodeFtp) {
   // Construct a valid SDCH dictionary from a VCDIFF dictionary.
@@ -518,7 +540,7 @@
   std::vector<Filter::FilterType> filter_types;
   filter_types.push_back(Filter::FILTER_TYPE_SDCH);
 
-  filter_context()->SetURL(GURL("ftp://" + kSampleDomain));
+  SetupFilterContextWithGURL(GURL("ftp://" + kSampleDomain));
   scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
 
   const size_t feed_block_size(100);
@@ -544,7 +566,7 @@
   std::vector<Filter::FilterType> filter_types;
   filter_types.push_back(Filter::FILTER_TYPE_SDCH);
 
-  filter_context()->SetURL(GURL("file://" + kSampleDomain));
+  SetupFilterContextWithGURL(GURL("file://" + kSampleDomain));
   scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
 
   const size_t feed_block_size(100);
@@ -570,7 +592,7 @@
   std::vector<Filter::FilterType> filter_types;
   filter_types.push_back(Filter::FILTER_TYPE_SDCH);
 
-  filter_context()->SetURL(GURL("about://" + kSampleDomain));
+  SetupFilterContextWithGURL(GURL("about://" + kSampleDomain));
   scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
 
   const size_t feed_block_size(100);
@@ -596,7 +618,7 @@
   std::vector<Filter::FilterType> filter_types;
   filter_types.push_back(Filter::FILTER_TYPE_SDCH);
 
-  filter_context()->SetURL(GURL("javascript://" + kSampleDomain));
+  SetupFilterContextWithGURL(GURL("javascript://" + kSampleDomain));
   scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
 
   const size_t feed_block_size(100);
@@ -622,7 +644,7 @@
   std::vector<Filter::FilterType> filter_types;
   filter_types.push_back(Filter::FILTER_TYPE_SDCH);
 
-  filter_context()->SetURL(GURL("http://" + kSampleDomain));
+  SetupFilterContextWithGURL(GURL("http://" + kSampleDomain));
   scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
 
   const size_t feed_block_size(100);
@@ -651,7 +673,7 @@
   // Decode with content arriving from the "wrong" domain.
   // This tests SdchManager::CanSet().
   GURL wrong_domain_url("http://www.wrongdomain.com");
-  filter_context()->SetURL(wrong_domain_url);
+  SetupFilterContextWithGURL(wrong_domain_url);
   scoped_ptr<Filter> filter(Filter::Factory(filter_types,  *filter_context()));
 
   size_t feed_block_size = 100;
@@ -696,7 +718,7 @@
   filter_types.push_back(Filter::FILTER_TYPE_SDCH);
 
   // Test decode the path data, arriving from a valid path.
-  filter_context()->SetURL(GURL(url_string + path));
+  SetupFilterContextWithGURL(GURL(url_string + path));
   scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
 
   size_t feed_block_size = 100;
@@ -708,7 +730,7 @@
   EXPECT_EQ(output, expanded_);
 
   // Test decode the path data, arriving from a invalid path.
-  filter_context()->SetURL(GURL(url_string));
+  SetupFilterContextWithGURL(GURL(url_string));
   filter.reset(Filter::Factory(filter_types, *filter_context()));
 
   feed_block_size = 100;
@@ -753,7 +775,7 @@
   filter_types.push_back(Filter::FILTER_TYPE_SDCH);
 
   // Test decode the port data, arriving from a valid port.
-  filter_context()->SetURL(GURL(url_string + ":" + port));
+  SetupFilterContextWithGURL(GURL(url_string + ":" + port));
   scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
 
   size_t feed_block_size = 100;
@@ -764,7 +786,7 @@
   EXPECT_EQ(output, expanded_);
 
   // Test decode the port data, arriving from a valid (default) port.
-  filter_context()->SetURL(GURL(url_string));  // Default port.
+  SetupFilterContextWithGURL(GURL(url_string));  // Default port.
   filter.reset(Filter::Factory(filter_types, *filter_context()));
 
   feed_block_size = 100;
@@ -775,7 +797,7 @@
   EXPECT_EQ(output, expanded_);
 
   // Test decode the port data, arriving from a invalid port.
-  filter_context()->SetURL(GURL(url_string + ":" + port + "1"));
+  SetupFilterContextWithGURL(GURL(url_string + ":" + port + "1"));
   filter.reset(Filter::Factory(filter_types, *filter_context()));
 
   feed_block_size = 100;
@@ -856,8 +878,8 @@
 };
 
 // Test that filters can be cascaded (chained) so that the output of one filter
-// is processed by the next one.  This is most critical for SDCH, which is
-// routinely followed by gzip (during encoding).  The filter we'll test for will
+// is processed by the next one. This is most critical for SDCH, which is
+// routinely followed by gzip (during encoding). The filter we'll test for will
 // do the gzip decoding first, and then decode the SDCH content.
 TEST_F(SdchFilterTest, FilterChaining) {
   // Construct a valid SDCH dictionary from a VCDIFF dictionary.
@@ -884,7 +906,7 @@
   CHECK_GT(kLargeInputBufferSize, gzip_compressed_sdch.size());
   CHECK_GT(kLargeInputBufferSize, sdch_compressed.size());
   CHECK_GT(kLargeInputBufferSize, expanded_.size());
-  filter_context()->SetURL(url);
+  SetupFilterContextWithGURL(url);
   scoped_ptr<Filter> filter(
       SdchFilterChainingTest::Factory(filter_types, *filter_context(),
                                       kLargeInputBufferSize));
@@ -962,16 +984,15 @@
   filter_types.push_back(Filter::FILTER_TYPE_SDCH);
 
   filter_context()->SetMimeType("anything/mime");
-  filter_context()->SetSdchResponse(true);
+  SetupFilterContextWithGURL(url);
+
   Filter::FixupEncodingTypes(*filter_context(), &filter_types);
   ASSERT_EQ(filter_types.size(), 2u);
   EXPECT_EQ(filter_types[0], Filter::FILTER_TYPE_SDCH);
   EXPECT_EQ(filter_types[1], Filter::FILTER_TYPE_GZIP_HELPING_SDCH);
 
   // First try with a large buffer (larger than test input, or compressed data).
-  filter_context()->SetURL(url);
-  scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
-
+    scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
 
   // Verify that chained filter is waiting for data.
   char tiny_output_buffer[10];
@@ -1020,7 +1041,7 @@
   filter_types.push_back(Filter::FILTER_TYPE_GZIP);
 
   filter_context()->SetMimeType("anything/mime");
-  filter_context()->SetSdchResponse(true);
+  SetupFilterContextWithGURL(url);
   Filter::FixupEncodingTypes(*filter_context(), &filter_types);
   ASSERT_EQ(filter_types.size(), 3u);
   EXPECT_EQ(filter_types[0], Filter::FILTER_TYPE_SDCH_POSSIBLE);
@@ -1028,10 +1049,8 @@
   EXPECT_EQ(filter_types[2], Filter::FILTER_TYPE_GZIP);
 
   // First try with a large buffer (larger than test input, or compressed data).
-  filter_context()->SetURL(url);
   scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
 
-
   // Verify that chained filter is waiting for data.
   char tiny_output_buffer[10];
   int tiny_output_size = sizeof(tiny_output_buffer);
@@ -1077,17 +1096,15 @@
   std::vector<Filter::FilterType> filter_types;
 
   filter_context()->SetMimeType("anything/mime");
-  filter_context()->SetSdchResponse(true);
+  SetupFilterContextWithGURL(url);
   Filter::FixupEncodingTypes(*filter_context(), &filter_types);
   ASSERT_EQ(filter_types.size(), 2u);
   EXPECT_EQ(filter_types[0], Filter::FILTER_TYPE_SDCH_POSSIBLE);
   EXPECT_EQ(filter_types[1], Filter::FILTER_TYPE_GZIP_HELPING_SDCH);
 
   // First try with a large buffer (larger than test input, or compressed data).
-  filter_context()->SetURL(url);
   scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
 
-
   // Verify that chained filter is waiting for data.
   char tiny_output_buffer[10];
   int tiny_output_size = sizeof(tiny_output_buffer);
@@ -1138,7 +1155,7 @@
   filter_types.push_back(Filter::FILTER_TYPE_GZIP);
 
   filter_context()->SetMimeType("anything/mime");
-  filter_context()->SetSdchResponse(true);
+  SetupFilterContextWithGURL(url);
   Filter::FixupEncodingTypes(*filter_context(), &filter_types);
   ASSERT_EQ(filter_types.size(), 3u);
   EXPECT_EQ(filter_types[0], Filter::FILTER_TYPE_SDCH_POSSIBLE);
@@ -1146,7 +1163,6 @@
   EXPECT_EQ(filter_types[2], Filter::FILTER_TYPE_GZIP);
 
   // First try with a large buffer (larger than test input, or compressed data).
-  filter_context()->SetURL(url);
   scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
 
   // Verify that chained filter is waiting for data.
@@ -1173,4 +1189,58 @@
   EXPECT_EQ(output, expanded_);
 }
 
+// Test to make sure we decode properly with an unexpected dictionary.
+TEST_F(SdchFilterTest, UnexpectedDictionary) {
+  // Setup a dictionary, add it to the filter context, and create a filter
+  // based on that dictionary.
+  const std::string kSampleDomain = "sdchtest.com";
+  std::string dictionary(NewSdchDictionary(kSampleDomain));
+  std::string url_string = "http://" + kSampleDomain;
+  GURL url(url_string);
+  EXPECT_TRUE(AddSdchDictionary(dictionary, url));
+
+  SetupFilterContextWithGURL(url);
+
+  std::vector<Filter::FilterType> filter_types;
+  filter_types.push_back(Filter::FILTER_TYPE_SDCH);
+  scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
+
+  // Setup another dictionary, expired. Don't add it to the filter context.
+  // Delete stored dictionaries first to handle platforms which only
+  // have room for a single dictionary.
+  sdch_manager_->ClearData();
+  std::string expired_dictionary(NewSdchExpiredDictionary(kSampleDomain));
+
+  // Don't use the Helper function since its insertion check is indeterminate
+  // for a Max-Age: 0 dictionary.
+  sdch_manager_->AddSdchDictionary(expired_dictionary, url);
+
+  std::string client_hash;
+  std::string server_hash;
+  SdchManager::GenerateHash(expired_dictionary, &client_hash, &server_hash);
+
+  // Make sure Max-Age: 0 shows up as expired.
+  scoped_ptr<base::SimpleTestClock> clock(new base::SimpleTestClock);
+  clock->SetNow(base::Time::Now());
+  clock->Advance(base::TimeDelta::FromMinutes(5));
+  SdchProblemCode problem_code;
+  scoped_ptr<SdchManager::DictionarySet> hash_set(
+      sdch_manager_->GetDictionarySetByHash(
+          url, server_hash, &problem_code).Pass());
+  ASSERT_TRUE(hash_set);
+  ASSERT_EQ(SDCH_OK, problem_code);
+
+  const_cast<SdchManager::Dictionary*>(
+      hash_set->GetDictionary(server_hash))->SetClockForTesting(
+      clock.Pass());
+
+  // Encode output with the second dictionary.
+  std::string sdch_compressed(NewSdchCompressedData(expired_dictionary));
+
+  // See if the filter decodes it.
+  std::string output;
+  EXPECT_TRUE(FilterTestData(sdch_compressed, 100, 100, filter.get(), &output));
+  EXPECT_EQ(expanded_, output);
+}
+
 }  // namespace net
diff --git a/net/ftp/ftp_network_transaction.cc b/net/ftp/ftp_network_transaction.cc
index 4cbde27..74bd6bf 100644
--- a/net/ftp/ftp_network_transaction.cc
+++ b/net/ftp/ftp_network_transaction.cc
@@ -965,14 +965,16 @@
   switch (GetErrorClass(response.status_code)) {
     case ERROR_CLASS_INITIATED:
       return Stop(ERR_INVALID_RESPONSE);
-    case ERROR_CLASS_OK:
-      if (!ExtractPortFromEPSVResponse( response, &data_connection_port_))
+    case ERROR_CLASS_OK: {
+      int port;
+      if (!ExtractPortFromEPSVResponse(response, &port))
         return Stop(ERR_INVALID_RESPONSE);
-      if (data_connection_port_ < 1024 ||
-          !IsPortAllowedByFtp(data_connection_port_))
+      if (port < 1024 || !IsPortAllowedByFtp(port))
         return Stop(ERR_UNSAFE_PORT);
+      data_connection_port_ = static_cast<uint16>(port);
       next_state_ = STATE_DATA_CONNECT;
       break;
+    }
     case ERROR_CLASS_INFO_NEEDED:
       return Stop(ERR_INVALID_RESPONSE);
     case ERROR_CLASS_TRANSIENT_ERROR:
@@ -999,14 +1001,16 @@
   switch (GetErrorClass(response.status_code)) {
     case ERROR_CLASS_INITIATED:
       return Stop(ERR_INVALID_RESPONSE);
-    case ERROR_CLASS_OK:
-      if (!ExtractPortFromPASVResponse(response, &data_connection_port_))
+    case ERROR_CLASS_OK: {
+      int port;
+      if (!ExtractPortFromPASVResponse(response, &port))
         return Stop(ERR_INVALID_RESPONSE);
-      if (data_connection_port_ < 1024 ||
-          !IsPortAllowedByFtp(data_connection_port_))
+      if (port < 1024 || !IsPortAllowedByFtp(port))
         return Stop(ERR_UNSAFE_PORT);
+      data_connection_port_ = static_cast<uint16>(port);
       next_state_ = STATE_DATA_CONNECT;
       break;
+    }
     case ERROR_CLASS_INFO_NEEDED:
       return Stop(ERR_INVALID_RESPONSE);
     case ERROR_CLASS_TRANSIENT_ERROR:
diff --git a/net/ftp/ftp_network_transaction.h b/net/ftp/ftp_network_transaction.h
index c8ed550..e350e16 100644
--- a/net/ftp/ftp_network_transaction.h
+++ b/net/ftp/ftp_network_transaction.h
@@ -8,6 +8,7 @@
 #include <string>
 #include <utility>
 
+#include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
@@ -245,7 +246,7 @@
   // with any trailing slash removed.
   std::string current_remote_directory_;
 
-  int data_connection_port_;
+  uint16 data_connection_port_;
 
   ClientSocketFactory* socket_factory_;
 
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index 20ffdd1..8cddaf5 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -1027,11 +1027,8 @@
     return OK;
   }
 
-  HostPortPair endpoint = HostPortPair(request_->url.HostNoBrackets(),
-                                       request_->url.EffectiveIntPort());
-  ProcessAlternateProtocol(session_,
-                           *response_.headers.get(),
-                           endpoint);
+  ProcessAlternateProtocol(session_, *response_.headers.get(),
+                           HostPortPair::FromURL(request_->url));
 
   int rv = HandleAuthChallenge();
   if (rv != OK)
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index d08d162..878406e 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -268,12 +268,15 @@
     base::MessageLoop::current()->RunUntilIdle();
   }
 
+  const char* GetAlternateProtocolFromParam() {
+    return
+        AlternateProtocolToString(AlternateProtocolFromNextProto(GetParam()));
+  }
+
   // This is the expected return from a current server advertising SPDY.
   std::string GetAlternateProtocolHttpHeader() {
-    return
-        std::string("Alternate-Protocol: 443:") +
-        AlternateProtocolToString(AlternateProtocolFromNextProto(GetParam())) +
-        "\r\n\r\n";
+    return std::string("Alternate-Protocol: 443:") +
+        GetAlternateProtocolFromParam() + "\r\n\r\n";
   }
 
   // Either |write_failure| specifies a write failure or |read_failure|
@@ -407,8 +410,7 @@
 INSTANTIATE_TEST_CASE_P(
     NextProto,
     HttpNetworkTransactionTest,
-    testing::Values(kProtoDeprecatedSPDY2,
-                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
+    testing::Values(kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
 
 namespace {
 
@@ -10107,10 +10109,12 @@
   };
   MockRead data_reads_1[] = {
     MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
-    MockRead("HTTP/1.1 200 OK\r\n"
-             "Alternate-Protocol: 443:npn-spdy/2\r\n"
-             "Proxy-Connection: close\r\n"
-             "\r\n"),
+    MockRead("HTTP/1.1 200 OK\r\n"),
+    MockRead("Alternate-Protocol: 443:"),
+    MockRead(GetAlternateProtocolFromParam()),
+    MockRead("\r\n"),
+    MockRead("Proxy-Connection: close\r\n"),
+    MockRead("\r\n"),
   };
   StaticSocketDataProvider data_1(data_reads_1, arraysize(data_reads_1),
                                   data_writes_1, arraysize(data_writes_1));
@@ -11402,8 +11406,7 @@
   // SPDY GET for HTTP URL (through the proxy, but not the tunnel).
   SpdyHeaderBlock req2_block;
   req2_block[spdy_util_.GetMethodKey()] = "GET";
-  req2_block[spdy_util_.GetPathKey()] =
-      spdy_util_.is_spdy2() ? http_url.c_str() : "/";
+  req2_block[spdy_util_.GetPathKey()] = "/";
   req2_block[spdy_util_.GetHostKey()] = "www.google.com:443";
   req2_block[spdy_util_.GetSchemeKey()] = "http";
   spdy_util_.MaybeAddVersionHeader(&req2_block);
diff --git a/net/http/http_proxy_client_socket_pool_unittest.cc b/net/http/http_proxy_client_socket_pool_unittest.cc
index 694d394..bdaf57f 100644
--- a/net/http/http_proxy_client_socket_pool_unittest.cc
+++ b/net/http/http_proxy_client_socket_pool_unittest.cc
@@ -42,7 +42,7 @@
 struct HttpProxyClientSocketPoolTestParams {
   HttpProxyClientSocketPoolTestParams()
       : proxy_type(HTTP),
-        protocol(kProtoSPDY3) {}
+        protocol(kProtoSPDY31) {}
 
   HttpProxyClientSocketPoolTestParams(
       HttpProxyType proxy_type,
@@ -342,12 +342,6 @@
     HttpProxyClientSocketPoolTests,
     HttpProxyClientSocketPoolTest,
     ::testing::Values(
-        HttpProxyClientSocketPoolTestParams(HTTP, kProtoDeprecatedSPDY2),
-        HttpProxyClientSocketPoolTestParams(HTTPS, kProtoDeprecatedSPDY2),
-        HttpProxyClientSocketPoolTestParams(SPDY, kProtoDeprecatedSPDY2),
-        HttpProxyClientSocketPoolTestParams(HTTP, kProtoSPDY3),
-        HttpProxyClientSocketPoolTestParams(HTTPS, kProtoSPDY3),
-        HttpProxyClientSocketPoolTestParams(SPDY, kProtoSPDY3),
         HttpProxyClientSocketPoolTestParams(HTTP, kProtoSPDY31),
         HttpProxyClientSocketPoolTestParams(HTTPS, kProtoSPDY31),
         HttpProxyClientSocketPoolTestParams(SPDY, kProtoSPDY31),
diff --git a/net/http/http_server_properties_impl.cc b/net/http/http_server_properties_impl.cc
index 65ecd11..1bf541b 100644
--- a/net/http/http_server_properties_impl.cc
+++ b/net/http/http_server_properties_impl.cc
@@ -67,7 +67,7 @@
   }
 
   // Attempt to find canonical servers.
-  int canonical_ports[] = { 80, 443 };
+  uint16 canonical_ports[] = { 80, 443 };
   for (size_t i = 0; i < canonical_suffixes_.size(); ++i) {
     std::string canonical_suffix = canonical_suffixes_[i];
     for (size_t j = 0; j < arraysize(canonical_ports); ++j) {
@@ -301,8 +301,14 @@
     const HostPortPair& server) {
   AlternateProtocolMap::iterator it = alternate_protocol_map_.Get(server);
   if (it == alternate_protocol_map_.end()) {
-    LOG(DFATAL) << "Trying to mark unknown alternate protocol broken.";
-    return;
+    if (!HasAlternateProtocol(server)) {
+      LOG(DFATAL) << "Trying to mark unknown alternate protocol broken.";
+      return;
+    }
+    // This server's alternate protocol information is coming from a canonical
+    // server. Add an entry in the map for this server explicitly so that
+    // it can be marked as broken.
+    it = alternate_protocol_map_.Put(server, GetAlternateProtocol(server));
   }
   it->second.is_broken = true;
   int count = ++broken_alternate_protocol_map_[server];
diff --git a/net/http/http_server_properties_impl_unittest.cc b/net/http/http_server_properties_impl_unittest.cc
index 1c016b7..3d1bacb 100644
--- a/net/http/http_server_properties_impl_unittest.cc
+++ b/net/http/http_server_properties_impl_unittest.cc
@@ -475,6 +475,23 @@
   EXPECT_FALSE(impl_.HasAlternateProtocol(test_host_port_pair));
 }
 
+TEST_F(AlternateProtocolServerPropertiesTest, CanonicalBroken2) {
+  HostPortPair test_host_port_pair("foo.c.youtube.com", 80);
+  HostPortPair canonical_port_pair("bar.c.youtube.com", 80);
+
+  AlternateProtocolInfo canonical_protocol(1234, QUIC, 1);
+
+  impl_.SetAlternateProtocol(canonical_port_pair,
+                             canonical_protocol.port,
+                             canonical_protocol.protocol,
+                             canonical_protocol.probability);
+
+  impl_.SetBrokenAlternateProtocol(test_host_port_pair);
+  AlternateProtocolInfo alternate =
+      impl_.GetAlternateProtocol(test_host_port_pair);
+  EXPECT_TRUE(alternate.is_broken);
+}
+
 TEST_F(AlternateProtocolServerPropertiesTest, ClearWithCanonical) {
   HostPortPair test_host_port_pair("foo.c.youtube.com", 80);
   HostPortPair canonical_port_pair("bar.c.youtube.com", 80);
diff --git a/net/http/http_server_properties_manager.cc b/net/http/http_server_properties_manager.cc
index 41b70b1..5773129 100644
--- a/net/http/http_server_properties_manager.cc
+++ b/net/http/http_server_properties_manager.cc
@@ -449,9 +449,8 @@
         continue;
       }
 
-      net::AlternateProtocolInfo port_alternate_protocol(port,
-                                                         protocol,
-                                                         probability);
+      net::AlternateProtocolInfo port_alternate_protocol(
+          static_cast<uint16>(port), protocol, probability);
       alternate_protocol_map->Put(server, port_alternate_protocol);
       ++count;
     } while (false);
diff --git a/net/http/http_stream_factory.cc b/net/http/http_stream_factory.cc
index 29d9b26..f84b80c 100644
--- a/net/http/http_stream_factory.cc
+++ b/net/http/http_stream_factory.cc
@@ -60,7 +60,7 @@
     }
 
     if (!base::StringToInt(port_protocol_vector[0], &port) ||
-        port <= 0 || port >= 1 << 16) {
+        port == 0 || !IsPortValid(port)) {
       DVLOG(1) << kAlternateProtocolHeader
                << " header has unrecognizable port: "
                << port_protocol_vector[0];
@@ -94,8 +94,8 @@
       return;
   }
 
-  http_server_properties->SetAlternateProtocol(host_port, port, protocol,
-                                               probability);
+  http_server_properties->SetAlternateProtocol(
+      host_port, static_cast<uint16>(port), protocol, probability);
 }
 
 GURL HttpStreamFactory::ApplyHostMappingRules(const GURL& url,
diff --git a/net/http/http_stream_factory_impl.cc b/net/http/http_stream_factory_impl.cc
index 8304694..8b12dba 100644
--- a/net/http/http_stream_factory_impl.cc
+++ b/net/http/http_stream_factory_impl.cc
@@ -184,8 +184,7 @@
   if (original_url.SchemeIs("ftp"))
     return kNoAlternateProtocol;
 
-  HostPortPair origin = HostPortPair(original_url.HostNoBrackets(),
-                                     original_url.EffectiveIntPort());
+  HostPortPair origin = HostPortPair::FromURL(original_url);
 
   HttpServerProperties& http_server_properties =
       *session_->http_server_properties();
diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc
index a11dd2e..8369443 100644
--- a/net/http/http_stream_factory_impl_job.cc
+++ b/net/http/http_stream_factory_impl_job.cc
@@ -132,13 +132,10 @@
 
 int HttpStreamFactoryImpl::Job::Preconnect(int num_streams) {
   DCHECK_GT(num_streams, 0);
-  HostPortPair origin_server =
-      HostPortPair(request_info_.url.HostNoBrackets(),
-                   request_info_.url.EffectiveIntPort());
   base::WeakPtr<HttpServerProperties> http_server_properties =
       session_->http_server_properties();
-  if (http_server_properties &&
-      http_server_properties->SupportsSpdy(origin_server)) {
+  if (http_server_properties && http_server_properties->SupportsSpdy(
+      HostPortPair::FromURL(request_info_.url))) {
     num_streams_ = 1;
   } else {
     num_streams_ = num_streams;
@@ -617,8 +614,7 @@
 }
 
 int HttpStreamFactoryImpl::Job::DoStart() {
-  int port = request_info_.url.EffectiveIntPort();
-  origin_ = HostPortPair(request_info_.url.HostNoBrackets(), port);
+  origin_ = HostPortPair::FromURL(request_info_.url);
   origin_url_ = stream_factory_->ApplyHostMappingRules(
       request_info_.url, &origin_);
 
@@ -628,14 +624,14 @@
                                  priority_));
 
   // Don't connect to restricted ports.
-  bool is_port_allowed = IsPortAllowedByDefault(port);
+  bool is_port_allowed = IsPortAllowedByDefault(origin_.port());
   if (request_info_.url.SchemeIs("ftp")) {
     // Never share connection with other jobs for FTP requests.
     DCHECK(!waiting_job_);
 
-    is_port_allowed = IsPortAllowedByFtp(port);
+    is_port_allowed = IsPortAllowedByFtp(origin_.port());
   }
-  if (!is_port_allowed && !IsPortAllowedByOverride(port)) {
+  if (!is_port_allowed && !IsPortAllowedByOverride(origin_.port())) {
     if (waiting_job_) {
       waiting_job_->Resume(this);
       waiting_job_ = NULL;
diff --git a/net/http/http_stream_factory_impl_request_unittest.cc b/net/http/http_stream_factory_impl_request_unittest.cc
index 587358d..32900f9 100644
--- a/net/http/http_stream_factory_impl_request_unittest.cc
+++ b/net/http/http_stream_factory_impl_request_unittest.cc
@@ -19,8 +19,7 @@
 INSTANTIATE_TEST_CASE_P(
     NextProto,
     HttpStreamFactoryImplRequestTest,
-    testing::Values(kProtoDeprecatedSPDY2,
-                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
+    testing::Values(kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
 
 namespace {
 
diff --git a/net/http/http_stream_factory_impl_unittest.cc b/net/http/http_stream_factory_impl_unittest.cc
index 68e9114..4ac5467 100644
--- a/net/http/http_stream_factory_impl_unittest.cc
+++ b/net/http/http_stream_factory_impl_unittest.cc
@@ -424,8 +424,7 @@
 INSTANTIATE_TEST_CASE_P(
     NextProto,
     HttpStreamFactoryTest,
-    testing::Values(kProtoDeprecatedSPDY2,
-                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
+    testing::Values(kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
 
 TEST_P(HttpStreamFactoryTest, PreconnectDirect) {
   for (size_t i = 0; i < arraysize(kTests); ++i) {
diff --git a/net/net.gyp b/net/net.gyp
index 3c9a520..da91a92 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -876,8 +876,12 @@
         '../testing/gmock.gyp:gmock',
       ],
       'sources': [
+        'base/captured_net_log_entry.cc',
+        'base/captured_net_log_entry.h',
         'base/capturing_net_log.cc',
         'base/capturing_net_log.h',
+        'base/capturing_net_log_observer.cc',
+        'base/capturing_net_log_observer.h',
         'base/load_timing_info_test_util.cc',
         'base/load_timing_info_test_util.h',
         'base/mock_file_stream.cc',
diff --git a/net/net.gypi b/net/net.gypi
index 337f016..cc9ff35 100644
--- a/net/net.gypi
+++ b/net/net.gypi
@@ -1236,8 +1236,8 @@
       'websockets/websocket_frame_parser.h',
       'websockets/websocket_handshake_constants.cc',
       'websockets/websocket_handshake_constants.h',
-      'websockets/websocket_handshake_handler.cc',
-      'websockets/websocket_handshake_handler.h',
+      'websockets/websocket_handshake_challenge.cc',
+      'websockets/websocket_handshake_challenge.h',
       'websockets/websocket_handshake_request_info.cc',
       'websockets/websocket_handshake_request_info.h',
       'websockets/websocket_handshake_response_info.cc',
@@ -1709,7 +1709,7 @@
       'websockets/websocket_extension_parser_test.cc',
       'websockets/websocket_frame_parser_test.cc',
       'websockets/websocket_frame_test.cc',
-      'websockets/websocket_handshake_handler_test.cc',
+      'websockets/websocket_handshake_challenge_test.cc',
       'websockets/websocket_handshake_stream_create_helper_test.cc',
       'websockets/websocket_inflater_test.cc',
       'websockets/websocket_stream_test.cc',
diff --git a/net/proxy/network_delegate_error_observer_unittest.cc b/net/proxy/network_delegate_error_observer_unittest.cc
index 5d2c501..da87f8d 100644
--- a/net/proxy/network_delegate_error_observer_unittest.cc
+++ b/net/proxy/network_delegate_error_observer_unittest.cc
@@ -77,10 +77,6 @@
   bool OnCanThrottleRequest(const URLRequest& request) const override {
     return false;
   }
-  int OnBeforeSocketStreamConnect(SocketStream* stream,
-                                  const CompletionCallback& callback) override {
-    return OK;
-  }
 
   bool got_pac_error_;
 };
diff --git a/net/proxy/proxy_config_service_android.cc b/net/proxy/proxy_config_service_android.cc
index f1a0b6c..50407fe 100644
--- a/net/proxy/proxy_config_service_android.cc
+++ b/net/proxy/proxy_config_service_android.cc
@@ -197,7 +197,8 @@
       : jni_delegate_(this),
         network_task_runner_(network_task_runner),
         jni_task_runner_(jni_task_runner),
-        get_property_callback_(get_property_callback) {
+        get_property_callback_(get_property_callback),
+        exclude_pac_url_(false) {
   }
 
   void SetupJNI() {
@@ -271,13 +272,22 @@
                               const std::vector<std::string>& exclusion_list) {
     DCHECK(OnJNIThread());
     ProxyConfig proxy_config;
-    CreateStaticProxyConfig(host, port, pac_url, exclusion_list, &proxy_config);
+    if (exclude_pac_url_) {
+      CreateStaticProxyConfig(host, port, "", exclusion_list, &proxy_config);
+    } else {
+      CreateStaticProxyConfig(host, port, pac_url, exclusion_list,
+          &proxy_config);
+    }
     network_task_runner_->PostTask(
         FROM_HERE,
         base::Bind(
             &Delegate::SetNewConfigOnNetworkThread, this, proxy_config));
   }
 
+  void set_exclude_pac_url(bool enabled) {
+    exclude_pac_url_ = enabled;
+  }
+
  private:
   friend class base::RefCountedThreadSafe<Delegate>;
 
@@ -344,6 +354,7 @@
   scoped_refptr<base::SequencedTaskRunner> jni_task_runner_;
   GetPropertyCallback get_property_callback_;
   ProxyConfig proxy_config_;
+  bool exclude_pac_url_;
 
   DISALLOW_COPY_AND_ASSIGN(Delegate);
 };
@@ -366,6 +377,10 @@
   return RegisterNativesImpl(env);
 }
 
+void ProxyConfigServiceAndroid::set_exclude_pac_url(bool enabled) {
+  delegate_->set_exclude_pac_url(enabled);
+}
+
 void ProxyConfigServiceAndroid::AddObserver(Observer* observer) {
   delegate_->AddObserver(observer);
 }
diff --git a/net/proxy/proxy_config_service_android.h b/net/proxy/proxy_config_service_android.h
index d642d37..cb15bc5 100644
--- a/net/proxy/proxy_config_service_android.h
+++ b/net/proxy/proxy_config_service_android.h
@@ -64,6 +64,11 @@
   // Register JNI bindings.
   static bool Register(JNIEnv* env);
 
+  // Android provides a local HTTP proxy that does PAC resolution. When this
+  // setting is enabled, the proxy config service ignores the PAC URL and uses
+  // the local proxy for all proxy resolution.
+  void set_exclude_pac_url(bool enabled);
+
   // ProxyConfigService:
   // Called only on the network thread.
   virtual void AddObserver(Observer* observer) override;
diff --git a/net/proxy/proxy_resolver_v8.cc b/net/proxy/proxy_resolver_v8.cc
index 24fbe9e..963153d 100644
--- a/net/proxy/proxy_resolver_v8.cc
+++ b/net/proxy/proxy_resolver_v8.cc
@@ -196,7 +196,7 @@
     return false;
 
   v8::HandleScope scope(isolate);
-  v8::Local<v8::String> str_object = object->ToString();
+  v8::Local<v8::String> str_object = object->ToString(isolate);
   if (str_object.IsEmpty())
     return false;
   *utf16_result = V8StringToUTF16(str_object);
@@ -211,7 +211,8 @@
   if (args.Length() == 0 || args[0].IsEmpty() || !args[0]->IsString())
     return false;
 
-  const base::string16 hostname_utf16 = V8StringToUTF16(args[0]->ToString());
+  const base::string16 hostname_utf16 =
+      V8StringToUTF16(v8::Local<v8::String>::Cast(args[0]));
 
   // If the hostname is already in ASCII, simply return it as is.
   if (base::IsStringASCII(hostname_utf16)) {
@@ -393,7 +394,7 @@
       return ERR_PAC_SCRIPT_FAILED;
     }
 
-    base::string16 ret_str = V8StringToUTF16(ret->ToString());
+    base::string16 ret_str = V8StringToUTF16(v8::Local<v8::String>::Cast(ret));
 
     if (!base::IsStringASCII(ret_str)) {
       // TODO(eroman): Rather than failing when a wide string is returned, we
@@ -656,7 +657,8 @@
       return;
     }
 
-    std::string ip_address_list = V8StringToUTF8(args[0]->ToString());
+    std::string ip_address_list =
+        V8StringToUTF8(v8::Local<v8::String>::Cast(args[0]));
     if (!base::IsStringASCII(ip_address_list)) {
       args.GetReturnValue().SetNull();
       return;
@@ -681,12 +683,14 @@
       return;
     }
 
-    std::string ip_address = V8StringToUTF8(args[0]->ToString());
+    std::string ip_address =
+        V8StringToUTF8(v8::Local<v8::String>::Cast(args[0]));
     if (!base::IsStringASCII(ip_address)) {
       args.GetReturnValue().Set(false);
       return;
     }
-    std::string ip_prefix = V8StringToUTF8(args[1]->ToString());
+    std::string ip_prefix =
+        V8StringToUTF8(v8::Local<v8::String>::Cast(args[1]));
     if (!base::IsStringASCII(ip_prefix)) {
       args.GetReturnValue().Set(false);
       return;
diff --git a/net/proxy/proxy_script_fetcher_impl_unittest.cc b/net/proxy/proxy_script_fetcher_impl_unittest.cc
index 2073d00..4c5bd4c 100644
--- a/net/proxy/proxy_script_fetcher_impl_unittest.cc
+++ b/net/proxy/proxy_script_fetcher_impl_unittest.cc
@@ -179,11 +179,6 @@
     return false;
   }
 
-  int OnBeforeSocketStreamConnect(SocketStream* stream,
-                                  const CompletionCallback& callback) override {
-    return OK;
-  }
-
   DISALLOW_COPY_AND_ASSIGN(BasicNetworkDelegate);
 };
 
diff --git a/net/proxy/proxy_server.cc b/net/proxy/proxy_server.cc
index 0b9ba67..78d5c3e 100644
--- a/net/proxy/proxy_server.cc
+++ b/net/proxy/proxy_server.cc
@@ -6,6 +6,7 @@
 
 #include <algorithm>
 
+#include "base/basictypes.h"
 #include "base/strings/string_util.h"
 #include "net/base/net_util.h"
 #include "net/http/http_util.h"
@@ -238,7 +239,7 @@
     if (port == -1)
       port = GetDefaultPortForScheme(scheme);
 
-    host_port_pair = HostPortPair(host, port);
+    host_port_pair = HostPortPair(host, static_cast<uint16>(port));
   }
 
   return ProxyServer(scheme, host_port_pair);
diff --git a/net/quic/congestion_control/pacing_sender.cc b/net/quic/congestion_control/pacing_sender.cc
index 8073c5b..7e9f81a 100644
--- a/net/quic/congestion_control/pacing_sender.cc
+++ b/net/quic/congestion_control/pacing_sender.cc
@@ -27,6 +27,11 @@
   sender_->SetFromConfig(config, is_server, using_pacing);
 }
 
+void PacingSender::ResumeConnectionState(
+    const CachedNetworkParameters& cached_network_params) {
+  sender_->ResumeConnectionState(cached_network_params);
+}
+
 void PacingSender::SetNumEmulatedConnections(int num_connections) {
   sender_->SetNumEmulatedConnections(num_connections);
 }
diff --git a/net/quic/congestion_control/pacing_sender.h b/net/quic/congestion_control/pacing_sender.h
index 4eb3dab..d7d3b2d 100644
--- a/net/quic/congestion_control/pacing_sender.h
+++ b/net/quic/congestion_control/pacing_sender.h
@@ -16,6 +16,7 @@
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
 #include "net/quic/congestion_control/send_algorithm_interface.h"
+#include "net/quic/crypto/cached_network_parameters.h"
 #include "net/quic/quic_bandwidth.h"
 #include "net/quic/quic_config.h"
 #include "net/quic/quic_protocol.h"
@@ -38,6 +39,8 @@
   void SetFromConfig(const QuicConfig& config,
                      bool is_server,
                      bool using_pacing) override;
+  void ResumeConnectionState(
+      const CachedNetworkParameters& cached_network_params) override;
   void SetNumEmulatedConnections(int num_connections) override;
   void OnCongestionEvent(bool rtt_updated,
                          QuicByteCount bytes_in_flight,
@@ -63,6 +66,7 @@
   bool InRecovery() const override;
   QuicByteCount GetSlowStartThreshold() const override;
   CongestionControlType GetCongestionControlType() const override;
+  // End implementation of SendAlgorithmInterface.
 
  private:
   scoped_ptr<SendAlgorithmInterface> sender_;  // Underlying sender.
diff --git a/net/quic/congestion_control/send_algorithm_interface.h b/net/quic/congestion_control/send_algorithm_interface.h
index 7195f81..322ff1d 100644
--- a/net/quic/congestion_control/send_algorithm_interface.h
+++ b/net/quic/congestion_control/send_algorithm_interface.h
@@ -12,6 +12,7 @@
 
 #include "base/basictypes.h"
 #include "net/base/net_export.h"
+#include "net/quic/crypto/cached_network_parameters.h"
 #include "net/quic/quic_bandwidth.h"
 #include "net/quic/quic_clock.h"
 #include "net/quic/quic_config.h"
@@ -113,6 +114,10 @@
   virtual QuicByteCount GetSlowStartThreshold() const = 0;
 
   virtual CongestionControlType GetCongestionControlType() const = 0;
+
+  // Called by the Session when we get a bandwidth estimate from the client.
+  virtual void ResumeConnectionState(
+      const CachedNetworkParameters& cached_network_params) = 0;
 };
 
 }  // namespace net
diff --git a/net/quic/congestion_control/tcp_cubic_sender.cc b/net/quic/congestion_control/tcp_cubic_sender.cc
index 2d0efd7..5fa1559 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender.cc
@@ -27,13 +27,12 @@
 const uint32 kDefaultNumConnections = 2;  // N-connection emulation.
 }  // namespace
 
-TcpCubicSender::TcpCubicSender(
-    const QuicClock* clock,
-    const RttStats* rtt_stats,
-    bool reno,
-    QuicPacketCount initial_tcp_congestion_window,
-    QuicPacketCount max_tcp_congestion_window,
-    QuicConnectionStats* stats)
+TcpCubicSender::TcpCubicSender(const QuicClock* clock,
+                               const RttStats* rtt_stats,
+                               bool reno,
+                               QuicPacketCount initial_tcp_congestion_window,
+                               QuicPacketCount max_tcp_congestion_window,
+                               QuicConnectionStats* stats)
     : hybrid_slow_start_(clock),
       cubic_(clock, stats),
       rtt_stats_(rtt_stats),
@@ -49,8 +48,8 @@
       slowstart_threshold_(max_tcp_congestion_window),
       previous_slowstart_threshold_(0),
       last_cutback_exited_slowstart_(false),
-      max_tcp_congestion_window_(max_tcp_congestion_window) {
-}
+      max_tcp_congestion_window_(max_tcp_congestion_window),
+      clock_(clock) {}
 
 TcpCubicSender::~TcpCubicSender() {
   UMA_HISTOGRAM_COUNTS("Net.QuicSession.FinalTcpCwnd", congestion_window_);
@@ -73,6 +72,26 @@
   }
 }
 
+void TcpCubicSender::ResumeConnectionState(
+    const CachedNetworkParameters& cached_network_params) {
+  // If the previous bandwidth estimate is less than an hour old, store in
+  // preparation for doing bandwidth resumption.
+  int64 seconds_since_estimate =
+      clock_->WallNow().ToUNIXSeconds() - cached_network_params.timestamp();
+  if (seconds_since_estimate > kNumSecondsPerHour) {
+    return;
+  }
+
+  QuicBandwidth bandwidth = QuicBandwidth::FromBytesPerSecond(
+      cached_network_params.bandwidth_estimate_bytes_per_second());
+  QuicTime::Delta rtt_ms =
+      QuicTime::Delta::FromMilliseconds(cached_network_params.min_rtt_ms());
+  congestion_window_ = bandwidth.ToBytesPerPeriod(rtt_ms) / kMaxPacketSize;
+
+  // TODO(rjshade): Set appropriate CWND when previous connection was in slow
+  // start at time of estimate.
+}
+
 void TcpCubicSender::SetNumEmulatedConnections(int num_connections) {
   num_connections_ = max(1, num_connections);
   cubic_.SetNumConnections(num_connections_);
diff --git a/net/quic/congestion_control/tcp_cubic_sender.h b/net/quic/congestion_control/tcp_cubic_sender.h
index a7507a2..eeb9331 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.h
+++ b/net/quic/congestion_control/tcp_cubic_sender.h
@@ -15,6 +15,7 @@
 #include "net/quic/congestion_control/hybrid_slow_start.h"
 #include "net/quic/congestion_control/prr_sender.h"
 #include "net/quic/congestion_control/send_algorithm_interface.h"
+#include "net/quic/crypto/cached_network_parameters.h"
 #include "net/quic/quic_bandwidth.h"
 #include "net/quic/quic_connection_stats.h"
 #include "net/quic/quic_protocol.h"
@@ -43,6 +44,8 @@
   void SetFromConfig(const QuicConfig& config,
                      bool is_server,
                      bool using_pacing) override;
+  void ResumeConnectionState(
+      const CachedNetworkParameters& cached_network_params) override;
   void SetNumEmulatedConnections(int num_connections) override;
   void OnCongestionEvent(bool rtt_updated,
                          QuicByteCount bytes_in_flight,
@@ -130,6 +133,8 @@
   // Maximum number of outstanding packets for tcp.
   QuicPacketCount max_tcp_congestion_window_;
 
+  const QuicClock* clock_;
+
   DISALLOW_COPY_AND_ASSIGN(TcpCubicSender);
 };
 
diff --git a/net/quic/congestion_control/tcp_cubic_sender_test.cc b/net/quic/congestion_control/tcp_cubic_sender_test.cc
index 427dd8c..e4737eb 100644
--- a/net/quic/congestion_control/tcp_cubic_sender_test.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender_test.cc
@@ -701,5 +701,32 @@
   EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
 }
 
+TEST_F(TcpCubicSenderTest, BandwidthResumption) {
+  // Test that when provided with CachedNetworkParameters and opted in to the
+  // bandwidth resumption experiment, that the TcpCubicSender sets initial CWND
+  // appropriately.
+
+  // Set some common values.
+  CachedNetworkParameters cached_network_params;
+  const QuicPacketCount kNumberOfPackets = 123;
+  const int kBandwidthEstimateBytesPerSecond =
+      kNumberOfPackets * kMaxPacketSize;
+  cached_network_params.set_bandwidth_estimate_bytes_per_second(
+      kBandwidthEstimateBytesPerSecond);
+  cached_network_params.set_min_rtt_ms(1000);
+
+  // Ensure that an old estimate is not used for bandwidth resumption.
+  cached_network_params.set_timestamp(clock_.WallNow().ToUNIXSeconds() -
+                                      (kNumSecondsPerHour + 1));
+  sender_->ResumeConnectionState(cached_network_params);
+  EXPECT_EQ(10u, sender_->congestion_window());
+
+  // If the estimate is new enough, make sure it is used.
+  cached_network_params.set_timestamp(clock_.WallNow().ToUNIXSeconds() -
+                                      (kNumSecondsPerHour - 1));
+  sender_->ResumeConnectionState(cached_network_params);
+  EXPECT_EQ(kNumberOfPackets, sender_->congestion_window());
+}
+
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/congestion_control/tcp_loss_algorithm.cc b/net/quic/congestion_control/tcp_loss_algorithm.cc
index 6cf56d8..9366105 100644
--- a/net/quic/congestion_control/tcp_loss_algorithm.cc
+++ b/net/quic/congestion_control/tcp_loss_algorithm.cc
@@ -40,7 +40,7 @@
       continue;
     }
 
-    LOG_IF(DFATAL, it->nack_count == 0)
+    LOG_IF(DFATAL, it->nack_count == 0 && it->sent_time.IsInitialized())
         << "All packets less than largest observed should have been nacked."
         << "sequence_number:" << sequence_number
         << " largest_observed:" << largest_observed;
diff --git a/net/quic/congestion_control/tcp_loss_algorithm_test.cc b/net/quic/congestion_control/tcp_loss_algorithm_test.cc
index 5819fb1..fe6a6ea 100644
--- a/net/quic/congestion_control/tcp_loss_algorithm_test.cc
+++ b/net/quic/congestion_control/tcp_loss_algorithm_test.cc
@@ -12,8 +12,14 @@
 #include "net/quic/test_tools/mock_clock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using std::vector;
+
 namespace net {
 namespace test {
+namespace {
+
+// Default packet length.
+const uint32 kDefaultLength = 1000;
 
 class TcpLossAlgorithmTest : public ::testing::Test {
  protected:
@@ -24,9 +30,16 @@
                          clock_.Now());
   }
 
+  ~TcpLossAlgorithmTest() override {
+    STLDeleteElements(&packets_);
+  }
+
   void SendDataPacket(QuicPacketSequenceNumber sequence_number) {
+    packets_.push_back(QuicPacket::NewDataPacket(
+        nullptr, kDefaultLength, false, PACKET_8BYTE_CONNECTION_ID, false,
+        PACKET_1BYTE_SEQUENCE_NUMBER));
     SerializedPacket packet(sequence_number, PACKET_1BYTE_SEQUENCE_NUMBER,
-                            nullptr, 0, new RetransmittableFrames());
+                            packets_.back(), 0, new RetransmittableFrames());
     unacked_packets_.AddSentPacket(packet, 0, NOT_RETRANSMISSION, clock_.Now(),
                                    1000, true);
   }
@@ -43,6 +56,7 @@
     }
   }
 
+  vector<QuicPacket*> packets_;
   QuicUnackedPacketMap unacked_packets_;
   TCPLossAlgorithm loss_algorithm_;
   RttStats rtt_stats_;
@@ -179,5 +193,6 @@
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
 
+}  // namespace
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/congestion_control/time_loss_algorithm.cc b/net/quic/congestion_control/time_loss_algorithm.cc
index 9dd9ae9..b5f90b7 100644
--- a/net/quic/congestion_control/time_loss_algorithm.cc
+++ b/net/quic/congestion_control/time_loss_algorithm.cc
@@ -46,8 +46,10 @@
     if (!it->in_flight) {
       continue;
     }
-    LOG_IF(DFATAL, it->nack_count == 0)
-        << "All packets less than largest observed should have been nacked.";
+    LOG_IF(DFATAL, it->nack_count == 0 && it->sent_time.IsInitialized())
+        << "All packets less than largest observed should have been nacked."
+        << "sequence_number:" << sequence_number
+        << " largest_observed:" << largest_observed;
 
     // Packets are sent in order, so break when we haven't waited long enough
     // to lose any more packets and leave the loss_time_ set for the timeout.
diff --git a/net/quic/congestion_control/time_loss_algorithm_test.cc b/net/quic/congestion_control/time_loss_algorithm_test.cc
index b964d28..1e9b7e5 100644
--- a/net/quic/congestion_control/time_loss_algorithm_test.cc
+++ b/net/quic/congestion_control/time_loss_algorithm_test.cc
@@ -12,8 +12,14 @@
 #include "net/quic/test_tools/mock_clock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using std::vector;
+
 namespace net {
 namespace test {
+namespace {
+
+// Default packet length.
+const uint32 kDefaultLength = 1000;
 
 class TimeLossAlgorithmTest : public ::testing::Test {
  protected:
@@ -24,9 +30,16 @@
                          clock_.Now());
   }
 
+  ~TimeLossAlgorithmTest() override {
+    STLDeleteElements(&packets_);
+  }
+
   void SendDataPacket(QuicPacketSequenceNumber sequence_number) {
+    packets_.push_back(QuicPacket::NewDataPacket(
+        nullptr, kDefaultLength, false, PACKET_8BYTE_CONNECTION_ID, false,
+        PACKET_1BYTE_SEQUENCE_NUMBER));
     SerializedPacket packet(sequence_number, PACKET_1BYTE_SEQUENCE_NUMBER,
-                            nullptr, 0, new RetransmittableFrames());
+                            packets_.back(), 0, new RetransmittableFrames());
     unacked_packets_.AddSentPacket(packet, 0, NOT_RETRANSMISSION, clock_.Now(),
                                    1000, true);
   }
@@ -43,6 +56,7 @@
     }
   }
 
+  vector<QuicPacket*> packets_;
   QuicUnackedPacketMap unacked_packets_;
   TimeLossAlgorithm loss_algorithm_;
   RttStats rtt_stats_;
@@ -134,5 +148,6 @@
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
 
+}  // namespace
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/crypto/common_cert_set.cc b/net/quic/crypto/common_cert_set.cc
index 09379f3..b2ea3a7 100644
--- a/net/quic/crypto/common_cert_set.cc
+++ b/net/quic/crypto/common_cert_set.cc
@@ -153,7 +153,7 @@
 
  private:
   CommonCertSetsQUIC() {}
-  virtual ~CommonCertSetsQUIC() {}
+  ~CommonCertSetsQUIC() override {}
 
   friend struct DefaultSingletonTraits<CommonCertSetsQUIC>;
   DISALLOW_COPY_AND_ASSIGN(CommonCertSetsQUIC);
diff --git a/net/quic/crypto/crypto_handshake_message.cc b/net/quic/crypto/crypto_handshake_message.cc
index 9125968..23e8ea2 100644
--- a/net/quic/crypto/crypto_handshake_message.cc
+++ b/net/quic/crypto/crypto_handshake_message.cc
@@ -302,8 +302,9 @@
                             static_cast<int>(it->second.size()));
         done = true;
         break;
+      case kSNI:
       case kUAID:
-        ret += it->second;
+        ret += "\"" + it->second + "\"";
         done = true;
         break;
     }
diff --git a/net/quic/crypto/crypto_protocol.h b/net/quic/crypto/crypto_protocol.h
index d010776..57a5508 100644
--- a/net/quic/crypto/crypto_protocol.h
+++ b/net/quic/crypto/crypto_protocol.h
@@ -71,6 +71,9 @@
 // FEC options
 const QuicTag kFHDR = TAG('F', 'H', 'D', 'R');   // FEC protect headers
 
+// Enable bandwidth resumption experiment.
+const QuicTag kBWRE = TAG('B', 'W', 'R', 'E');  // Bandwidth resumption.
+
 // Proof types (i.e. certificate types)
 // NOTE: although it would be silly to do so, specifying both kX509 and kX59R
 // is allowed and is equivalent to specifying only kX509.
diff --git a/net/quic/quic_client_session.cc b/net/quic/quic_client_session.cc
index 274099c..97d6c3b 100644
--- a/net/quic/quic_client_session.cc
+++ b/net/quic/quic_client_session.cc
@@ -13,6 +13,7 @@
 #include "base/values.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_errors.h"
+#include "net/base/network_activity_monitor.h"
 #include "net/http/transport_security_state.h"
 #include "net/quic/crypto/proof_verifier_chromium.h"
 #include "net/quic/crypto/quic_server_info.h"
@@ -633,6 +634,18 @@
             "Net.QuicSession.TimedOutWithOpenStreams.ConsecutiveTLPCount",
             connection()->sent_packet_manager().consecutive_tlp_count());
       }
+      if (connection()->sent_packet_manager().HasUnackedPackets()) {
+        UMA_HISTOGRAM_TIMES(
+            "Net.QuicSession.LocallyTimedOutWithOpenStreams."
+                "TimeSinceLastReceived.UnackedPackets",
+            NetworkActivityMonitor::GetInstance()->GetTimeSinceLastReceived());
+      } else {
+        UMA_HISTOGRAM_TIMES(
+            "Net.QuicSession.LocallyTimedOutWithOpenStreams."
+                "TimeSinceLastReceived.NoUnackedPackets",
+            NetworkActivityMonitor::GetInstance()->GetTimeSinceLastReceived());
+      }
+
     } else {
       UMA_HISTOGRAM_COUNTS(
           "Net.QuicSession.ConnectionClose.NumOpenStreams.HandshakeTimedOut",
diff --git a/net/quic/quic_client_session_test.cc b/net/quic/quic_client_session_test.cc
index 66583b8..88beca7 100644
--- a/net/quic/quic_client_session_test.cc
+++ b/net/quic/quic_client_session_test.cc
@@ -52,6 +52,8 @@
                                             /*is_secure=*/false,
                                             PRIVACY_MODE_DISABLED),
         &crypto_config_, nullptr);
+    // Advance the time, because timers do not like uninitialized times.
+    connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
   }
 
   void TearDown() override { session_.CloseSessionOnError(ERR_ABORTED); }
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index fd9ec5f..62cbc64 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -282,6 +282,11 @@
   max_undecryptable_packets_ = config.max_undecryptable_packets();
 }
 
+void QuicConnection::ResumeConnectionState(
+    const CachedNetworkParameters& cached_network_params) {
+  sent_packet_manager_.ResumeConnectionState(cached_network_params);
+}
+
 void QuicConnection::SetNumOpenStreams(size_t num_streams) {
   sent_packet_manager_.SetNumOpenStreams(num_streams);
 }
@@ -911,10 +916,6 @@
     } else {
       // Send an ack much more quickly for crypto handshake packets.
       QuicTime::Delta delayed_ack_time = sent_packet_manager_.DelayedAckTime();
-      if (last_stream_frames_.size() == 1 &&
-          last_stream_frames_[0].stream_id == kCryptoStreamId) {
-        delayed_ack_time = QuicTime::Delta::Zero();
-      }
       ack_alarm_->Set(clock_->ApproximateNow().Add(delayed_ack_time));
       DVLOG(1) << "Ack timer set; next packet or timer will trigger ACK.";
     }
@@ -1449,6 +1450,13 @@
            << QuicUtils::StringToHexASCIIDump(
                packet->serialized_packet.packet->AsStringPiece());
 
+  QuicTime packet_send_time = QuicTime::Zero();
+  if (FLAGS_quic_record_send_time_before_write) {
+    // Measure the RTT from before the write begins to avoid underestimating the
+    // min_rtt_, especially in cases where the thread blocks or gets swapped out
+    // during the WritePacket below.
+    packet_send_time = clock_->Now();
+  }
   WriteResult result = writer_->WritePacket(encrypted->data(),
                                             encrypted->length(),
                                             self_address().address(),
@@ -1467,7 +1475,16 @@
       return false;
     }
   }
-  QuicTime now = clock_->Now();
+  if (!FLAGS_quic_record_send_time_before_write) {
+    packet_send_time = clock_->Now();
+  }
+  if (!packet_send_time.IsInitialized()) {
+    // TODO(jokulik): This is only needed because of the two code paths for
+    // initializing packet_send_time.  Once "quic_record_send_time_before_write"
+    // is deprecated, this check can be removed.
+    LOG(DFATAL) << "The packet send time should never be zero. "
+                << "This is a programming bug, please report it.";
+  }
   if (result.status != WRITE_STATUS_ERROR && debug_visitor_.get() != nullptr) {
     // Pass the write result to the visitor.
     debug_visitor_->OnPacketSent(packet->serialized_packet,
@@ -1475,14 +1492,17 @@
                                  packet->encryption_level,
                                  packet->transmission_type,
                                  *encrypted,
-                                 now);
+                                 packet_send_time);
   }
   if (packet->transmission_type == NOT_RETRANSMISSION) {
-    time_of_last_sent_new_packet_ = now;
+    time_of_last_sent_new_packet_ = packet_send_time;
   }
   SetPingAlarm();
-  DVLOG(1) << ENDPOINT << "time of last sent packet: "
-           << now.ToDebuggingValue();
+  DVLOG(1) << ENDPOINT << "time "
+           << (FLAGS_quic_record_send_time_before_write ?
+               "we began writing " : "we finished writing ")
+           << "last sent packet: "
+           << packet_send_time.ToDebuggingValue();
 
   // TODO(ianswett): Change the sequence number length and other packet creator
   // options by a more explicit API than setting a struct value directly,
@@ -1494,7 +1514,7 @@
   bool reset_retransmission_alarm = sent_packet_manager_.OnPacketSent(
       &packet->serialized_packet,
       packet->original_sequence_number,
-      now,
+      packet_send_time,
       encrypted->length(),
       packet->transmission_type,
       IsRetransmittable(*packet));
@@ -1585,6 +1605,12 @@
 
 void QuicConnection::OnHandshakeComplete() {
   sent_packet_manager_.SetHandshakeConfirmed();
+  // The client should immediately ack the SHLO to confirm the handshake is
+  // complete with the server.
+  if (!is_server_ && !ack_queued_) {
+    ack_alarm_->Cancel();
+    ack_alarm_->Set(clock_->ApproximateNow());
+  }
 }
 
 void QuicConnection::SendOrQueuePacket(QueuedPacket packet) {
@@ -1598,8 +1624,6 @@
   sent_entropy_manager_.RecordPacketEntropyHash(
       packet.serialized_packet.sequence_number,
       packet.serialized_packet.entropy_hash);
-  LOG_IF(DFATAL, !queued_packets_.empty() && !writer_->IsWriteBlocked())
-      << "Packets should only be left queued if we're write blocked.";
   if (!WritePacket(&packet)) {
     queued_packets_.push_back(packet);
   }
diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h
index 96f5cbc..abab048 100644
--- a/net/quic/quic_connection.h
+++ b/net/quic/quic_connection.h
@@ -24,6 +24,7 @@
 #include <string>
 #include <vector>
 
+#include "base/basictypes.h"
 #include "base/logging.h"
 #include "net/base/iovec.h"
 #include "net/base/ip_endpoint.h"
@@ -258,6 +259,11 @@
   // Sets connection parameters from the supplied |config|.
   void SetFromConfig(const QuicConfig& config);
 
+  // Called by the Session when the client has provided CachedNetworkParameters.
+  // Virtual for tests.
+  virtual void ResumeConnectionState(
+      const CachedNetworkParameters& cached_network_params);
+
   // Sets the number of active streams on the connection for congestion control.
   void SetNumOpenStreams(size_t num_streams);
 
@@ -689,7 +695,7 @@
   IPEndPoint self_address_;
   IPEndPoint peer_address_;
   // Used to store latest peer port to possibly migrate to later.
-  int migrating_peer_port_;
+  uint16 migrating_peer_port_;
 
   // True if the last packet has gotten far enough in the framer to be
   // decrypted.
@@ -783,8 +789,8 @@
   // This is used for timeouts, and does not indicate the packet was processed.
   QuicTime time_of_last_received_packet_;
 
-  // The last time a new (non-retransmitted) packet was sent for this
-  // connection.
+  // The last time this connection began sending a new (non-retransmitted)
+  // packet.
   QuicTime time_of_last_sent_new_packet_;
 
   // Sequence number of the last sent packet.  Packets are guaranteed to be sent
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index 4e58dfd..ede61c8 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -67,7 +67,7 @@
   }
 
   bool GenerateCongestionFeedback(
-      QuicCongestionFeedbackFrame* congestion_feedback) {
+      QuicCongestionFeedbackFrame* congestion_feedback) override {
     if (feedback_ == nullptr) {
       return false;
     }
@@ -95,6 +95,7 @@
 
   // QuicEncrypter interface.
   bool SetKey(StringPiece key) override { return true; }
+
   bool SetNoncePrefix(StringPiece nonce_prefix) override { return true; }
 
   bool Encrypt(StringPiece nonce,
@@ -149,6 +150,7 @@
 
   // QuicDecrypter interface
   bool SetKey(StringPiece key) override { return true; }
+
   bool SetNoncePrefix(StringPiece nonce_prefix) override { return true; }
 
   bool Decrypt(StringPiece nonce,
@@ -258,7 +260,7 @@
 
 class TestPacketWriter : public QuicPacketWriter {
  public:
-  explicit TestPacketWriter(QuicVersion version)
+  TestPacketWriter(QuicVersion version, MockClock *clock)
       : version_(version),
         framer_(SupportedVersions(version_)),
         last_packet_size_(0),
@@ -268,7 +270,9 @@
         final_bytes_of_last_packet_(0),
         final_bytes_of_previous_packet_(0),
         use_tagging_decrypter_(false),
-        packets_write_attempts_(0) {
+        packets_write_attempts_(0),
+        clock_(clock),
+        write_pause_time_delta_(QuicTime::Delta::Zero()) {
   }
 
   // QuicPacketWriter interface
@@ -297,6 +301,10 @@
       return WriteResult(WRITE_STATUS_BLOCKED, -1);
     }
     last_packet_size_ = packet.length();
+
+    if (!write_pause_time_delta_.IsZero()) {
+      clock_->AdvanceTime(write_pause_time_delta_);
+    }
     return WriteResult(WRITE_STATUS_OK, last_packet_size_);
   }
 
@@ -310,6 +318,11 @@
 
   void BlockOnNextWrite() { block_on_next_write_ = true; }
 
+  // Sets the amount of time that the writer should before the actual write.
+  void SetWritePauseTimeDelta(QuicTime::Delta delta) {
+    write_pause_time_delta_ = delta;
+  }
+
   const QuicPacketHeader& header() { return framer_.header(); }
 
   size_t frame_count() const { return framer_.num_frames(); }
@@ -390,6 +403,10 @@
   uint32 final_bytes_of_previous_packet_;
   bool use_tagging_decrypter_;
   uint32 packets_write_attempts_;
+  MockClock *clock_;
+  // If non-zero, the clock will pause during WritePacket for this amount of
+  // time.
+  QuicTime::Delta write_pause_time_delta_;
 
   DISALLOW_COPY_AND_ASSIGN(TestPacketWriter);
 };
@@ -597,7 +614,7 @@
   MockPacketWriterFactory(QuicPacketWriter* writer) {
     ON_CALL(*this, Create(_)).WillByDefault(Return(writer));
   }
-  virtual ~MockPacketWriterFactory() {}
+  ~MockPacketWriterFactory() override {}
 
   MOCK_CONST_METHOD1(Create, QuicPacketWriter*(QuicConnection* connection));
 };
@@ -611,7 +628,7 @@
         send_algorithm_(new StrictMock<MockSendAlgorithm>),
         loss_algorithm_(new MockLossAlgorithm()),
         helper_(new TestConnectionHelper(&clock_, &random_generator_)),
-        writer_(new TestPacketWriter(version())),
+        writer_(new TestPacketWriter(version(), &clock_)),
         factory_(writer_.get()),
         connection_(connection_id_, IPEndPoint(), helper_.get(),
                     factory_, false, version()),
@@ -974,6 +991,10 @@
     EXPECT_CALL(visitor_, OnWriteBlocked()).Times(AtLeast(1));
   }
 
+  void SetWritePauseTimeDelta(QuicTime::Delta delta) {
+    writer_->SetWritePauseTimeDelta(delta);
+  }
+
   void CongestionBlockWrites() {
     EXPECT_CALL(*send_algorithm_,
                 TimeUntilSend(_, _, _)).WillRepeatedly(
@@ -1548,6 +1569,74 @@
   EXPECT_EQ(7u, least_unacked());
 }
 
+// If FLAGS_quic_record_send_time_before_write is disabled, QuicConnection
+// should record the packet sen-tdime after the packet is sent.
+TEST_P(QuicConnectionTest, RecordSentTimeAfterPacketSent) {
+  ValueRestore<bool> old_flag(&FLAGS_quic_record_send_time_before_write, false);
+  // We're using a MockClock for the tests, so we have complete control over the
+  // time.
+  // Our recorded timestamp for the last packet sent time will be passed in to
+  // the send_algorithm.  Make sure that it is set to the correct value.
+  QuicTime actual_recorded_send_time = QuicTime::Zero();
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+      .WillOnce(DoAll(SaveArg<0>(&actual_recorded_send_time), Return(true)));
+
+  // First send without any pause and check the result.
+  QuicTime expected_recorded_send_time = clock_.Now();
+  connection_.SendStreamDataWithString(1, "foo", 0, !kFin, nullptr);
+  EXPECT_EQ(expected_recorded_send_time, actual_recorded_send_time)
+      << "Expected time = " << expected_recorded_send_time.ToDebuggingValue()
+      << ".  Actual time = " << actual_recorded_send_time.ToDebuggingValue();
+
+  // Now pause during the write, and check the results.
+  actual_recorded_send_time = QuicTime::Zero();
+  const QuicTime::Delta kWritePauseTimeDelta =
+      QuicTime::Delta::FromMilliseconds(5000);
+  SetWritePauseTimeDelta(kWritePauseTimeDelta);
+  expected_recorded_send_time = clock_.Now().Add(kWritePauseTimeDelta);
+
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+      .WillOnce(DoAll(SaveArg<0>(&actual_recorded_send_time), Return(true)));
+  connection_.SendStreamDataWithString(2, "baz", 0, !kFin, nullptr);
+  EXPECT_EQ(expected_recorded_send_time, actual_recorded_send_time)
+      << "Expected time = " << expected_recorded_send_time.ToDebuggingValue()
+      << ".  Actual time = " << actual_recorded_send_time.ToDebuggingValue();
+}
+
+// If FLAGS_quic_record_send_time_before_write is enabled, QuicConnection should
+// record the the packet sent-time prior to sending the packet.
+TEST_P(QuicConnectionTest, RecordSentTimeBeforePacketSent) {
+  ValueRestore<bool> old_flag(&FLAGS_quic_record_send_time_before_write, true);
+  // We're using a MockClock for the tests, so we have complete control over the
+  // time.
+  // Our recorded timestamp for the last packet sent time will be passed in to
+  // the send_algorithm.  Make sure that it is set to the correct value.
+  QuicTime actual_recorded_send_time = QuicTime::Zero();
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+      .WillOnce(DoAll(SaveArg<0>(&actual_recorded_send_time), Return(true)));
+
+  // First send without any pause and check the result.
+  QuicTime expected_recorded_send_time = clock_.Now();
+  connection_.SendStreamDataWithString(1, "foo", 0, !kFin, nullptr);
+  EXPECT_EQ(expected_recorded_send_time, actual_recorded_send_time)
+      << "Expected time = " << expected_recorded_send_time.ToDebuggingValue()
+      << ".  Actual time = " << actual_recorded_send_time.ToDebuggingValue();
+
+  // Now pause during the write, and check the results.
+  actual_recorded_send_time = QuicTime::Zero();
+  const QuicTime::Delta kWritePauseTimeDelta =
+      QuicTime::Delta::FromMilliseconds(5000);
+  SetWritePauseTimeDelta(kWritePauseTimeDelta);
+  expected_recorded_send_time = clock_.Now();
+
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _))
+      .WillOnce(DoAll(SaveArg<0>(&actual_recorded_send_time), Return(true)));
+  connection_.SendStreamDataWithString(2, "baz", 0, !kFin, nullptr);
+  EXPECT_EQ(expected_recorded_send_time, actual_recorded_send_time)
+      << "Expected time = " << expected_recorded_send_time.ToDebuggingValue()
+      << ".  Actual time = " << actual_recorded_send_time.ToDebuggingValue();
+}
+
 TEST_P(QuicConnectionTest, FECSending) {
   // All packets carry version info till version is negotiated.
   QuicPacketCreator* creator =
@@ -1565,7 +1654,8 @@
   creator->set_max_packet_length(length);
 
   // Send 4 protected data packets, which should also trigger 1 FEC packet.
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(5);
+  EXPECT_CALL(*send_algorithm_,
+              OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)).Times(5);
   // The first stream frame will have 2 fewer overhead bytes than the other 3.
   const string payload(payload_length * 4 + 2, 'a');
   connection_.SendStreamDataWithStringWithFec(1, payload, 0, !kFin, nullptr);
@@ -1601,7 +1691,8 @@
       &connection_)->IsFecEnabled());
 
   // 1 Data and 1 FEC packet.
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
+  EXPECT_CALL(*send_algorithm_,
+              OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)).Times(2);
   connection_.SendStreamDataWithStringWithFec(3, "foo", 0, !kFin, nullptr);
 
   const QuicTime::Delta retransmission_time =
@@ -1620,8 +1711,9 @@
   EXPECT_TRUE(QuicConnectionPeer::GetPacketCreator(
       &connection_)->IsFecEnabled());
 
-  // 1 Data and 1 FEC packet.
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(6);
+  // 3 Data and 3 FEC packets.
+  EXPECT_CALL(*send_algorithm_,
+              OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)).Times(6);
   connection_.SendStreamDataWithStringWithFec(3, "foo", 0, !kFin, nullptr);
   // Send some more data afterwards to ensure early retransmit doesn't trigger.
   connection_.SendStreamDataWithStringWithFec(3, "foo", 3, !kFin, nullptr);
@@ -1648,8 +1740,9 @@
   EXPECT_TRUE(QuicConnectionPeer::GetPacketCreator(
       &connection_)->IsFecEnabled());
 
-  // 1 Data and 1 FEC packet.
-  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(6);
+  // 3 Data and 3 FEC packet.
+  EXPECT_CALL(*send_algorithm_,
+              OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)).Times(6);
   connection_.SendStreamDataWithStringWithFec(3, "foo", 0, !kFin, nullptr);
   // Send some more data afterwards to ensure early retransmit doesn't trigger.
   connection_.SendStreamDataWithStringWithFec(3, "foo", 3, !kFin, nullptr);
@@ -3070,22 +3163,25 @@
   EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
 }
 
-TEST_P(QuicConnectionTest, SendEarlyDelayedAckForCrypto) {
-  QuicTime ack_time = clock_.ApproximateNow();
+TEST_P(QuicConnectionTest, SendDelayedAckOnHandshakeConfirmed) {
   EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
-  EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
-  // Process a packet from the crypto stream, which is frame1_'s default.
   ProcessPacket(1);
-  // Check if delayed ack timer is running for the expected interval.
+  // Check that ack is sent and that delayed ack alarm is set.
+  EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+  QuicTime ack_time = clock_.ApproximateNow().Add(DefaultDelayedAckTime());
+  EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
+
+  // Completing the handshake as the server does nothing.
+  QuicConnectionPeer::SetIsServer(&connection_, true);
+  connection_.OnHandshakeComplete();
   EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
   EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline());
-  // Simulate delayed ack alarm firing.
-  connection_.GetAckAlarm()->Fire();
-  // Check that ack is sent and that delayed ack alarm is reset.
-  EXPECT_EQ(2u, writer_->frame_count());
-  EXPECT_FALSE(writer_->stop_waiting_frames().empty());
-  EXPECT_FALSE(writer_->ack_frames().empty());
-  EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
+
+  // Complete the handshake as the client decreases the delayed ack time to 0ms.
+  QuicConnectionPeer::SetIsServer(&connection_, false);
+  connection_.OnHandshakeComplete();
+  EXPECT_TRUE(connection_.GetAckAlarm()->IsSet());
+  EXPECT_EQ(clock_.ApproximateNow(), connection_.GetAckAlarm()->deadline());
 }
 
 TEST_P(QuicConnectionTest, SendDelayedAckOnSecondPacket) {
diff --git a/net/quic/quic_crypto_client_stream_test.cc b/net/quic/quic_crypto_client_stream_test.cc
index 1df2313..8e14d77 100644
--- a/net/quic/quic_crypto_client_stream_test.cc
+++ b/net/quic/quic_crypto_client_stream_test.cc
@@ -34,6 +34,8 @@
         stream_(new QuicCryptoClientStream(server_id_, session_.get(), nullptr,
                                            &crypto_config_)) {
     session_->SetCryptoStream(stream_.get());
+    // Advance the time, because timers do not like uninitialized times.
+    connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
   }
 
   void CompleteCryptoHandshake() {
@@ -128,8 +130,8 @@
 
   // Advance time 5 years to ensure that we pass the expiry time of the cached
   // server config.
-  reinterpret_cast<MockClock*>(const_cast<QuicClock*>(connection_->clock()))
-      ->AdvanceTime(QuicTime::Delta::FromSeconds(60 * 60 * 24 * 365 * 5));
+  connection_->AdvanceTime(
+      QuicTime::Delta::FromSeconds(60 * 60 * 24 * 365 * 5));
 
   // Check that a client hello was sent and that CryptoConnect doesn't fail
   // with an error.
diff --git a/net/quic/quic_crypto_server_stream.cc b/net/quic/quic_crypto_server_stream.cc
index 1d62376..c4b5893 100644
--- a/net/quic/quic_crypto_server_stream.cc
+++ b/net/quic/quic_crypto_server_stream.cc
@@ -245,8 +245,8 @@
 void QuicCryptoServerStream::OverrideQuicConfigDefaults(QuicConfig* config) {
 }
 
-CachedNetworkParameters*
-QuicCryptoServerStream::get_previous_cached_network_params() {
+const CachedNetworkParameters*
+QuicCryptoServerStream::previous_cached_network_params() const {
   return previous_cached_network_params_.get();
 }
 
diff --git a/net/quic/quic_crypto_server_stream.h b/net/quic/quic_crypto_server_stream.h
index 09d9bd8..f88affe 100644
--- a/net/quic/quic_crypto_server_stream.h
+++ b/net/quic/quic_crypto_server_stream.h
@@ -82,6 +82,8 @@
   void set_previous_cached_network_params(
       CachedNetworkParameters cached_network_params);
 
+  const CachedNetworkParameters* previous_cached_network_params() const;
+
  protected:
   virtual QuicErrorCode ProcessClientHello(
       const CryptoHandshakeMessage& message,
@@ -93,8 +95,6 @@
   // before going through the parameter negotiation step.
   virtual void OverrideQuicConfigDefaults(QuicConfig* config);
 
-  CachedNetworkParameters* get_previous_cached_network_params();
-
  private:
   friend class test::CryptoTestUtils;
 
diff --git a/net/quic/quic_flags.cc b/net/quic/quic_flags.cc
index 47d58ce..e737933 100644
--- a/net/quic/quic_flags.cc
+++ b/net/quic/quic_flags.cc
@@ -54,3 +54,14 @@
 // If true, QUIC connections will delay moving to forward security until the
 // client starts sending foward secure encrypted packets.
 bool FLAGS_enable_quic_delay_forward_security = true;
+
+// Do not flip this flag.  jokulik plans more testing and additional monitoring
+// before the flag can go the auto-flip process.
+//
+// If true, record the timestamp for the last sent new packet before the call to
+// WritePacket, rather than after in QUIC.
+bool FLAGS_quic_record_send_time_before_write = false;
+
+// If true, enables the QUIC bandwidth resumption experiment (triggered by
+// Chrome/Finch).
+bool FLAGS_quic_enable_bandwidth_resumption_experiment = true;
diff --git a/net/quic/quic_flags.h b/net/quic/quic_flags.h
index a75f79b..2ffe618 100644
--- a/net/quic/quic_flags.h
+++ b/net/quic/quic_flags.h
@@ -20,5 +20,8 @@
 NET_EXPORT_PRIVATE extern bool FLAGS_allow_truncated_connection_ids_for_quic;
 NET_EXPORT_PRIVATE extern bool FLAGS_quic_too_many_outstanding_packets;
 NET_EXPORT_PRIVATE extern bool FLAGS_enable_quic_delay_forward_security;
+NET_EXPORT_PRIVATE extern bool FLAGS_quic_record_send_time_before_write;
+NET_EXPORT_PRIVATE
+extern bool FLAGS_quic_enable_bandwidth_resumption_experiment;
 
 #endif  // NET_QUIC_QUIC_FLAGS_H_
diff --git a/net/quic/quic_packet_creator_test.cc b/net/quic/quic_packet_creator_test.cc
index 4e03e3a..578acea 100644
--- a/net/quic/quic_packet_creator_test.cc
+++ b/net/quic/quic_packet_creator_test.cc
@@ -87,8 +87,7 @@
     server_framer_.set_visitor(&framer_visitor_);
   }
 
-  virtual ~QuicPacketCreatorTest() override {
-  }
+  ~QuicPacketCreatorTest() override {}
 
   void ProcessPacket(QuicPacket* packet) {
     scoped_ptr<QuicEncryptedPacket> encrypted(
diff --git a/net/quic/quic_packet_generator_test.cc b/net/quic/quic_packet_generator_test.cc
index 3f2472c..ac99144 100644
--- a/net/quic/quic_packet_generator_test.cc
+++ b/net/quic/quic_packet_generator_test.cc
@@ -33,7 +33,7 @@
 class MockDelegate : public QuicPacketGenerator::DelegateInterface {
  public:
   MockDelegate() {}
-  virtual ~MockDelegate() override {}
+  ~MockDelegate() override {}
 
   MOCK_METHOD3(ShouldGeneratePacket,
                bool(TransmissionType transmission_type,
@@ -116,7 +116,7 @@
         packet6_(0, PACKET_1BYTE_SEQUENCE_NUMBER, nullptr, 0, nullptr),
         packet7_(0, PACKET_1BYTE_SEQUENCE_NUMBER, nullptr, 0, nullptr) {}
 
-  virtual ~QuicPacketGeneratorTest() override {
+  ~QuicPacketGeneratorTest() override {
     delete packet_.packet;
     delete packet_.retransmittable_frames;
     delete packet2_.packet;
diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc
index 5aa831e..b631b07 100644
--- a/net/quic/quic_protocol.cc
+++ b/net/quic/quic_protocol.cc
@@ -704,7 +704,8 @@
       transmission_type(NOT_RETRANSMISSION),
       all_transmissions(nullptr),
       in_flight(false),
-      is_unackable(false) {}
+      is_unackable(false),
+      is_fec_packet(false) {}
 
 TransmissionInfo::TransmissionInfo(
     RetransmittableFrames* retransmittable_frames,
@@ -719,6 +720,7 @@
       transmission_type(transmission_type),
       all_transmissions(nullptr),
       in_flight(false),
-      is_unackable(false) {}
+      is_unackable(false),
+      is_fec_packet(false) {}
 
 }  // namespace net
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index 00064ff..4cd53a9 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -1099,6 +1099,8 @@
   bool in_flight;
   // True if the packet can never be acked, so it can be removed.
   bool is_unackable;
+  // True if the packet is an FEC packet.
+  bool is_fec_packet;
 };
 
 }  // namespace net
diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc
index 7978fed..142871e 100644
--- a/net/quic/quic_sent_packet_manager.cc
+++ b/net/quic/quic_sent_packet_manager.cc
@@ -163,6 +163,11 @@
   }
 }
 
+void QuicSentPacketManager::ResumeConnectionState(
+    const CachedNetworkParameters& cached_network_params) {
+  send_algorithm_->ResumeConnectionState(cached_network_params);
+}
+
 void QuicSentPacketManager::SetNumOpenStreams(size_t num_streams) {
   if (n_connection_simulation_) {
     // Ensure the number of connections is between 1 and 5.
@@ -323,6 +328,9 @@
         (retransmission_type == ALL_UNACKED_RETRANSMISSION ||
          frames->encryption_level() == ENCRYPTION_INITIAL)) {
       MarkForRetransmission(sequence_number, retransmission_type);
+    } else if (it->is_fec_packet) {
+      // Remove FEC packets from the packet map, since we can't retransmit them.
+      unacked_packets_.RemoveFromInFlight(sequence_number);
     }
   }
 }
@@ -549,12 +557,18 @@
   }
 
   // Only track packets as in flight that the send algorithm wants us to track.
+  // Since FEC packets should also be counted towards the congestion window,
+  // consider them as retransmittable for the purposes of congestion control.
+  HasRetransmittableData has_congestion_controlled_data =
+      serialized_packet->packet->is_fec_packet() ?
+      HAS_RETRANSMITTABLE_DATA : has_retransmittable_data;
   const bool in_flight =
       send_algorithm_->OnPacketSent(sent_time,
                                     unacked_packets_.bytes_in_flight(),
                                     sequence_number,
                                     bytes,
-                                    has_retransmittable_data);
+                                    has_congestion_controlled_data);
+
   unacked_packets_.AddSentPacket(*serialized_packet,
                                  original_sequence_number,
                                  transmission_type,
diff --git a/net/quic/quic_sent_packet_manager.h b/net/quic/quic_sent_packet_manager.h
index 2a3ea64..2a94e09 100644
--- a/net/quic/quic_sent_packet_manager.h
+++ b/net/quic/quic_sent_packet_manager.h
@@ -16,6 +16,7 @@
 #include "net/quic/congestion_control/loss_detection_interface.h"
 #include "net/quic/congestion_control/rtt_stats.h"
 #include "net/quic/congestion_control/send_algorithm_interface.h"
+#include "net/quic/crypto/cached_network_parameters.h"
 #include "net/quic/quic_ack_notifier_manager.h"
 #include "net/quic/quic_protocol.h"
 #include "net/quic/quic_sustained_bandwidth_recorder.h"
@@ -99,6 +100,10 @@
 
   virtual void SetFromConfig(const QuicConfig& config);
 
+  // Pass the CachedNetworkParameters to the send algorithm.
+  void ResumeConnectionState(
+      const CachedNetworkParameters& cached_network_params);
+
   void SetNumOpenStreams(size_t num_streams);
 
   void SetHandshakeConfirmed() { handshake_confirmed_ = true; }
@@ -111,6 +116,13 @@
   bool IsUnacked(QuicPacketSequenceNumber sequence_number) const;
 
   // Requests retransmission of all unacked packets of |retransmission_type|.
+  // The behavior of this method depends on the value of |retransmission_type|:
+  // ALL_UNACKED_RETRANSMISSION - All unacked packets will be retransmitted.
+  // This can happen, for example, after a version negotiation packet has been
+  // received and all packets needs to be retransmitted with the new version.
+  // ALL_INITIAL_RETRANSMISSION - Only initially encrypted packets will be
+  // retransmitted. This can happen, for example, when a CHLO has been rejected
+  // and the previously encrypted data needs to be encrypted with a new key.
   void RetransmitUnackedPackets(TransmissionType retransmission_type);
 
   // Retransmits the oldest pending packet there is still a tail loss probe
diff --git a/net/quic/quic_sent_packet_manager_test.cc b/net/quic/quic_sent_packet_manager_test.cc
index d710120..c1e6f20 100644
--- a/net/quic/quic_sent_packet_manager_test.cc
+++ b/net/quic/quic_sent_packet_manager_test.cc
@@ -64,9 +64,7 @@
     EXPECT_CALL(*send_algorithm_, InRecovery()).Times(AnyNumber());
   }
 
-  virtual ~QuicSentPacketManagerTest() override {
-    STLDeleteElements(&packets_);
-  }
+  ~QuicSentPacketManagerTest() override { STLDeleteElements(&packets_); }
 
   QuicByteCount BytesInFlight() {
     return QuicSentPacketManagerPeer::GetBytesInFlight(&manager_);
@@ -216,7 +214,7 @@
   void SendFecPacket(QuicPacketSequenceNumber sequence_number) {
     EXPECT_CALL(*send_algorithm_,
                 OnPacketSent(_, BytesInFlight(), sequence_number,
-                             kDefaultLength, NO_RETRANSMITTABLE_DATA))
+                             kDefaultLength, HAS_RETRANSMITTABLE_DATA))
                     .Times(1).WillOnce(Return(true));
     SerializedPacket packet(CreateFecPacket(sequence_number));
     manager_.OnPacketSent(&packet, 0, clock_.Now(),
diff --git a/net/quic/quic_server_session.cc b/net/quic/quic_server_session.cc
index 1d48182..e0defd6 100644
--- a/net/quic/quic_server_session.cc
+++ b/net/quic/quic_server_session.cc
@@ -37,14 +37,29 @@
 
 void QuicServerSession::OnConfigNegotiated() {
   QuicSession::OnConfigNegotiated();
-  if (!FLAGS_enable_quic_fec ||
-      !config()->HasReceivedConnectionOptions() ||
-      !ContainsQuicTag(config()->ReceivedConnectionOptions(), kFHDR)) {
+
+  if (!config()->HasReceivedConnectionOptions()) {
     return;
   }
-  // kFHDR config maps to FEC protection always for headers stream.
-  // TODO(jri): Add crypto stream in addition to headers for kHDR.
-  headers_stream_->set_fec_policy(FEC_PROTECT_ALWAYS);
+
+  // If the client has provided a bandwidth estimate from the same serving
+  // region, then pass it to the sent packet manager in preparation for possible
+  // bandwidth resumption.
+  const CachedNetworkParameters* cached_network_params =
+      crypto_stream_->previous_cached_network_params();
+  if (FLAGS_quic_enable_bandwidth_resumption_experiment &&
+      cached_network_params != nullptr &&
+      ContainsQuicTag(config()->ReceivedConnectionOptions(), kBWRE) &&
+      cached_network_params->serving_region() == serving_region_) {
+    connection()->ResumeConnectionState(*cached_network_params);
+  }
+
+  if (FLAGS_enable_quic_fec &&
+      ContainsQuicTag(config()->ReceivedConnectionOptions(), kFHDR)) {
+    // kFHDR config maps to FEC protection always for headers stream.
+    // TODO(jri): Add crypto stream in addition to headers for kHDR.
+    headers_stream_->set_fec_policy(FEC_PROTECT_ALWAYS);
+  }
 }
 
 void QuicServerSession::OnConnectionClosed(QuicErrorCode error,
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc
index 2318ab4..e4b163f 100644
--- a/net/quic/quic_session.cc
+++ b/net/quic/quic_session.cc
@@ -48,8 +48,8 @@
     session_->PostProcessAfterData();
   }
 
-  void OnWindowUpdateFrames(const vector<QuicWindowUpdateFrame>& frames)
-      override {
+  void OnWindowUpdateFrames(
+      const vector<QuicWindowUpdateFrame>& frames) override {
     session_->OnWindowUpdateFrames(frames);
     session_->PostProcessAfterData();
   }
diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc
index d14d875..d953678 100644
--- a/net/quic/quic_session_test.cc
+++ b/net/quic/quic_session_test.cc
@@ -54,8 +54,7 @@
       : QuicCryptoStream(session) {
   }
 
-  virtual void OnHandshakeMessage(
-      const CryptoHandshakeMessage& message) override {
+  void OnHandshakeMessage(const CryptoHandshakeMessage& message) override {
     encryption_established_ = true;
     handshake_confirmed_ = true;
     CryptoHandshakeMessage msg;
@@ -94,7 +93,7 @@
 
   using ReliableQuicStream::CloseWriteSide;
 
-  virtual uint32 ProcessData(const char* data, uint32 data_len) override {
+  uint32 ProcessData(const char* data, uint32 data_len) override {
     return data_len;
   }
 
@@ -131,17 +130,15 @@
     InitializeSession();
   }
 
-  virtual TestCryptoStream* GetCryptoStream() override {
-    return &crypto_stream_;
-  }
+  TestCryptoStream* GetCryptoStream() override { return &crypto_stream_; }
 
-  virtual TestStream* CreateOutgoingDataStream() override {
+  TestStream* CreateOutgoingDataStream() override {
     TestStream* stream = new TestStream(GetNextStreamId(), this);
     ActivateStream(stream);
     return stream;
   }
 
-  virtual TestStream* CreateIncomingDataStream(QuicStreamId id) override {
+  TestStream* CreateIncomingDataStream(QuicStreamId id) override {
     return new TestStream(id, this);
   }
 
@@ -153,7 +150,7 @@
     return QuicSession::GetIncomingDataStream(stream_id);
   }
 
-  virtual QuicConsumedData WritevData(
+  QuicConsumedData WritevData(
       QuicStreamId id,
       const IOVector& data,
       QuicStreamOffset offset,
@@ -223,6 +220,7 @@
         "Fas6LMcVC6Q8QLlHYbXBpdNFuGbuZGUnav5C-2I_-46lL0NGg3GewxGKGHvHEfoyn"
         "EFFlEYHsBQ98rXImL8ySDycdLEFvBPdtctPmWCfTxwmoSMLHU2SCVDhbqMWU5b0yr"
         "JBCScs_ejbKaqBDoB7ZGxTvqlrB__2ZmnHHjCr8RgMRtKNtIeuZAo ";
+    connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
   }
 
   void CheckClosedStreams() {
diff --git a/net/quic/quic_stream_sequencer_test.cc b/net/quic/quic_stream_sequencer_test.cc
index 8c90c9f..43a105b 100644
--- a/net/quic/quic_stream_sequencer_test.cc
+++ b/net/quic/quic_stream_sequencer_test.cc
@@ -44,7 +44,7 @@
                                                 const string& details));
   MOCK_METHOD1(Reset, void(QuicRstStreamErrorCode error));
   MOCK_METHOD0(OnCanWrite, void());
-  virtual QuicPriority EffectivePriority() const override {
+  QuicPriority EffectivePriority() const override {
     return QuicUtils::HighestPriority();
   }
   virtual bool IsFlowControlEnabled() const {
diff --git a/net/quic/quic_time.h b/net/quic/quic_time.h
index 53e5ebe..62bf582 100644
--- a/net/quic/quic_time.h
+++ b/net/quic/quic_time.h
@@ -17,6 +17,8 @@
 
 namespace net {
 
+static const int kNumSecondsPerMinute = 60;
+static const int kNumSecondsPerHour = kNumSecondsPerMinute * 60;
 static const uint64 kNumMicrosPerSecond = base::Time::kMicrosecondsPerSecond;
 static const uint64 kNumMicrosPerMilli =
     base::Time::kMicrosecondsPerMillisecond;
diff --git a/net/quic/quic_unacked_packet_map.cc b/net/quic/quic_unacked_packet_map.cc
index 04eb1b8..bbff3c9 100644
--- a/net/quic/quic_unacked_packet_map.cc
+++ b/net/quic/quic_unacked_packet_map.cc
@@ -53,6 +53,9 @@
                         packet.sequence_number_length,
                         transmission_type,
                         sent_time);
+  DCHECK(packet.packet != nullptr);
+  info.is_fec_packet = packet.packet->is_fec_packet();
+
   if (old_sequence_number == 0) {
     if (packet.retransmittable_frames != nullptr &&
         packet.retransmittable_frames->HasCryptoHandshake() == IS_HANDSHAKE) {
diff --git a/net/quic/quic_unacked_packet_map_test.cc b/net/quic/quic_unacked_packet_map_test.cc
index d31ce44..7840495 100644
--- a/net/quic/quic_unacked_packet_map_test.cc
+++ b/net/quic/quic_unacked_packet_map_test.cc
@@ -8,6 +8,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 using std::min;
+using std::vector;
 
 namespace net {
 namespace test {
@@ -23,16 +24,26 @@
       : now_(QuicTime::Zero().Add(QuicTime::Delta::FromMilliseconds(1000))) {
   }
 
+  ~QuicUnackedPacketMapTest() override {
+    STLDeleteElements(&packets_);
+  }
+
   SerializedPacket CreateRetransmittablePacket(
       QuicPacketSequenceNumber sequence_number) {
+    packets_.push_back(QuicPacket::NewDataPacket(
+        nullptr, kDefaultLength, false, PACKET_8BYTE_CONNECTION_ID, false,
+        PACKET_1BYTE_SEQUENCE_NUMBER));
     return SerializedPacket(sequence_number, PACKET_1BYTE_SEQUENCE_NUMBER,
-                            nullptr, 0, new RetransmittableFrames());
+                            packets_.back(), 0, new RetransmittableFrames());
   }
 
   SerializedPacket CreateNonRetransmittablePacket(
       QuicPacketSequenceNumber sequence_number) {
+    packets_.push_back(QuicPacket::NewDataPacket(
+        nullptr, kDefaultLength, false, PACKET_8BYTE_CONNECTION_ID, false,
+        PACKET_1BYTE_SEQUENCE_NUMBER));
     return SerializedPacket(sequence_number, PACKET_1BYTE_SEQUENCE_NUMBER,
-                            nullptr, 0, nullptr);
+                            packets_.back(), 0, nullptr);
   }
 
   void VerifyInFlightPackets(QuicPacketSequenceNumber* packets,
@@ -94,7 +105,7 @@
           << " packets[" << i << "]:" << packets[i];
     }
   }
-
+  vector<QuicPacket*> packets_;
   QuicUnackedPacketMap unacked_packets_;
   QuicTime now_;
 };
@@ -185,8 +196,8 @@
 
   unacked_packets_.RemoveFromInFlight(2);
   QuicPacketSequenceNumber unacked2[] = { 1 };
-  VerifyUnackedPackets(unacked, arraysize(unacked2));
-  VerifyInFlightPackets(unacked, arraysize(unacked2));
+  VerifyUnackedPackets(unacked2, arraysize(unacked2));
+  VerifyInFlightPackets(unacked2, arraysize(unacked2));
   VerifyRetransmittablePackets(nullptr, 0);
 
   unacked_packets_.RemoveFromInFlight(1);
diff --git a/net/quic/test_tools/crypto_test_utils.cc b/net/quic/test_tools/crypto_test_utils.cc
index 814be7b..b24316f 100644
--- a/net/quic/test_tools/crypto_test_utils.cc
+++ b/net/quic/test_tools/crypto_test_utils.cc
@@ -214,6 +214,8 @@
     QuicCryptoServerStream* server,
     const FakeClientOptions& options) {
   PacketSavingConnection* client_conn = new PacketSavingConnection(false);
+  // Advance the time, because timers do not like uninitialized times.
+  client_conn->AdvanceTime(QuicTime::Delta::FromSeconds(1));
   TestClientSession client_session(client_conn, DefaultQuicConfig());
   QuicCryptoClientConfig crypto_config;
 
diff --git a/net/quic/test_tools/mock_quic_dispatcher.h b/net/quic/test_tools/mock_quic_dispatcher.h
index f923790..4945724 100644
--- a/net/quic/test_tools/mock_quic_dispatcher.h
+++ b/net/quic/test_tools/mock_quic_dispatcher.h
@@ -22,7 +22,7 @@
                      PacketWriterFactory* packet_writer_factory,
                      QuicConnectionHelperInterface* helper);
 
-  virtual ~MockQuicDispatcher();
+  ~MockQuicDispatcher() override;
 
   MOCK_METHOD3(ProcessPacket, void(const IPEndPoint& server_address,
                                    const IPEndPoint& client_address,
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index fa987de..9df03eb 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -10,6 +10,7 @@
 #include <string>
 #include <vector>
 
+#include "base/basictypes.h"
 #include "base/strings/string_piece.h"
 #include "net/quic/congestion_control/loss_detection_interface.h"
 #include "net/quic/congestion_control/send_algorithm_interface.h"
@@ -31,7 +32,7 @@
 namespace test {
 
 static const QuicConnectionId kTestConnectionId = 42;
-static const int kTestPort = 123;
+static const uint16 kTestPort = 123;
 static const uint32 kInitialStreamFlowControlWindowForTest =
     32 * 1024;  // 32 KB
 static const uint32 kInitialSessionFlowControlWindowForTest =
@@ -150,7 +151,7 @@
 class MockFramerVisitor : public QuicFramerVisitorInterface {
  public:
   MockFramerVisitor();
-  virtual ~MockFramerVisitor();
+  ~MockFramerVisitor() override;
 
   MOCK_METHOD1(OnError, void(QuicFramer* framer));
   // The constructor sets this up to return false by default.
@@ -225,7 +226,7 @@
 class MockConnectionVisitor : public QuicConnectionVisitorInterface {
  public:
   MockConnectionVisitor();
-  virtual ~MockConnectionVisitor();
+  ~MockConnectionVisitor() override;
 
   MOCK_METHOD1(OnStreamFrames, void(const std::vector<QuicStreamFrame>& frame));
   MOCK_METHOD1(OnWindowUpdateFrames,
@@ -293,7 +294,7 @@
   // Uses a Mock helper, ConnectionId of 42, and 127.0.0.1:123.
   MockConnection(bool is_server, const QuicVersionVector& supported_versions);
 
-  virtual ~MockConnection();
+  ~MockConnection() override;
 
   // If the constructor that uses a MockHelper has been used then this method
   // will advance the time of the MockClock.
@@ -324,7 +325,7 @@
     QuicConnection::ProcessUdpPacket(self_address, peer_address, packet);
   }
 
-  virtual bool OnProtocolVersionMismatch(QuicVersion version) override {
+  bool OnProtocolVersionMismatch(QuicVersion version) override {
     return false;
   }
 
@@ -355,7 +356,7 @@
 class MockSession : public QuicSession {
  public:
   explicit MockSession(QuicConnection* connection);
-  virtual ~MockSession();
+  ~MockSession() override;
   MOCK_METHOD2(OnConnectionClosed, void(QuicErrorCode error, bool from_peer));
   MOCK_METHOD1(CreateIncomingDataStream, QuicDataStream*(QuicStreamId id));
   MOCK_METHOD0(GetCryptoStream, QuicCryptoStream*());
@@ -388,14 +389,14 @@
 class TestSession : public QuicSession {
  public:
   TestSession(QuicConnection* connection, const QuicConfig& config);
-  virtual ~TestSession();
+  ~TestSession() override;
 
   MOCK_METHOD1(CreateIncomingDataStream, QuicDataStream*(QuicStreamId id));
   MOCK_METHOD0(CreateOutgoingDataStream, QuicDataStream*());
 
   void SetCryptoStream(QuicCryptoStream* stream);
 
-  virtual QuicCryptoStream* GetCryptoStream() override;
+  QuicCryptoStream* GetCryptoStream() override;
 
  private:
   QuicCryptoStream* crypto_stream_;
@@ -406,7 +407,7 @@
 class TestClientSession : public QuicClientSessionBase {
  public:
   TestClientSession(QuicConnection* connection, const QuicConfig& config);
-  virtual ~TestClientSession();
+  ~TestClientSession() override;
 
   // QuicClientSessionBase
   MOCK_METHOD1(OnProofValid,
@@ -420,7 +421,7 @@
 
   void SetCryptoStream(QuicCryptoStream* stream);
 
-  virtual QuicCryptoStream* GetCryptoStream() override;
+  QuicCryptoStream* GetCryptoStream() override;
 
  private:
   QuicCryptoStream* crypto_stream_;
@@ -431,7 +432,7 @@
 class MockPacketWriter : public QuicPacketWriter {
  public:
   MockPacketWriter();
-  virtual ~MockPacketWriter();
+  ~MockPacketWriter() override;
 
   MOCK_METHOD4(WritePacket,
                WriteResult(const char* buffer,
@@ -449,7 +450,7 @@
 class MockSendAlgorithm : public SendAlgorithmInterface {
  public:
   MockSendAlgorithm();
-  virtual ~MockSendAlgorithm();
+  ~MockSendAlgorithm() override;
 
   MOCK_METHOD3(SetFromConfig, void(const QuicConfig& config,
                                    bool is_server,
@@ -482,6 +483,7 @@
   MOCK_CONST_METHOD0(InRecovery, bool());
   MOCK_CONST_METHOD0(GetSlowStartThreshold, QuicByteCount());
   MOCK_CONST_METHOD0(GetCongestionControlType, CongestionControlType());
+  MOCK_METHOD1(ResumeConnectionState, void(const CachedNetworkParameters&));
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockSendAlgorithm);
@@ -490,7 +492,7 @@
 class MockLossAlgorithm : public LossDetectionInterface {
  public:
   MockLossAlgorithm();
-  virtual ~MockLossAlgorithm();
+  ~MockLossAlgorithm() override;
 
   MOCK_CONST_METHOD0(GetLossDetectionType, LossDetectionType());
   MOCK_METHOD4(DetectLostPackets,
@@ -520,7 +522,7 @@
 class MockEntropyCalculator : public TestEntropyCalculator {
  public:
   MockEntropyCalculator();
-  virtual ~MockEntropyCalculator();
+  ~MockEntropyCalculator() override;
 
   MOCK_CONST_METHOD1(
       EntropyHash,
@@ -542,7 +544,7 @@
 
  protected:
   // Object is ref counted.
-  virtual ~MockAckNotifierDelegate();
+  ~MockAckNotifierDelegate() override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockAckNotifierDelegate);
@@ -552,7 +554,7 @@
       public QuicSentPacketManager::NetworkChangeVisitor {
  public:
   MockNetworkChangeVisitor();
-  virtual ~MockNetworkChangeVisitor();
+  ~MockNetworkChangeVisitor() override;
 
   MOCK_METHOD0(OnCongestionWindowChange, void());
 
diff --git a/net/socket/client_socket_pool_manager.cc b/net/socket/client_socket_pool_manager.cc
index b996127..bc7d111 100644
--- a/net/socket/client_socket_pool_manager.cc
+++ b/net/socket/client_socket_pool_manager.cc
@@ -91,9 +91,7 @@
   bool using_ssl = request_url.SchemeIs("https") ||
       request_url.SchemeIs("wss") || force_spdy_over_ssl;
 
-  HostPortPair origin_host_port =
-      HostPortPair(request_url.HostNoBrackets(),
-                   request_url.EffectiveIntPort());
+  HostPortPair origin_host_port = HostPortPair::FromURL(request_url);
 
   if (!using_ssl && session->params().testing_fixed_http_port != 0) {
     origin_host_port.set_port(session->params().testing_fixed_http_port);
diff --git a/net/socket/server_socket.cc b/net/socket/server_socket.cc
index da89b46..7cf6c64 100644
--- a/net/socket/server_socket.cc
+++ b/net/socket/server_socket.cc
@@ -17,7 +17,7 @@
 }
 
 int ServerSocket::ListenWithAddressAndPort(const std::string& address_string,
-                                           int port,
+                                           uint16 port,
                                            int backlog) {
   IPAddressNumber address_number;
   if (!ParseIPLiteralToNumber(address_string, &address_number)) {
diff --git a/net/socket/server_socket.h b/net/socket/server_socket.h
index 4b9ca8e..828b399 100644
--- a/net/socket/server_socket.h
+++ b/net/socket/server_socket.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
 #include "net/base/completion_callback.h"
 #include "net/base/net_export.h"
@@ -30,7 +31,7 @@
   // Subclasses may override this function if |address_string| is in a different
   // format, for example, unix domain socket path.
   virtual int ListenWithAddressAndPort(const std::string& address_string,
-                                       int port,
+                                       uint16 port,
                                        int backlog);
 
   // Gets current address the socket is bound to.
diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc
index 5ae4eee..308de2e 100644
--- a/net/socket/socket_test_util.cc
+++ b/net/socket/socket_test_util.cc
@@ -682,7 +682,7 @@
       new MockUDPClientSocket(data_provider, net_log));
   data_provider->set_socket(socket.get());
   if (bind_type == DatagramSocket::RANDOM_BIND)
-    socket->set_source_port(rand_int_cb.Run(1025, 65535));
+    socket->set_source_port(static_cast<uint16>(rand_int_cb.Run(1025, 65535)));
   return socket.Pass();
 }
 
@@ -1917,7 +1917,7 @@
   data_provider->set_delegate(socket->AsWeakPtr());
   udp_client_sockets().push_back(socket.get());
   if (bind_type == DatagramSocket::RANDOM_BIND)
-    socket->set_source_port(rand_int_cb.Run(1025, 65535));
+    socket->set_source_port(static_cast<uint16>(rand_int_cb.Run(1025, 65535)));
   return socket.Pass();
 }
 
diff --git a/net/socket/socket_test_util.h b/net/socket/socket_test_util.h
index 7bccdae..7b45c0c 100644
--- a/net/socket/socket_test_util.h
+++ b/net/socket/socket_test_util.h
@@ -881,13 +881,13 @@
   void OnReadComplete(const MockRead& data) override;
   void OnConnectComplete(const MockConnect& data) override;
 
-  void set_source_port(int port) { source_port_ = port; }
+  void set_source_port(uint16 port) { source_port_ = port; }
 
  private:
   bool connected_;
   IPEndPoint peer_address_;
   DeterministicSocketHelper helper_;
-  int source_port_;  // Ephemeral source port.
+  uint16 source_port_;  // Ephemeral source port.
 
   DISALLOW_COPY_AND_ASSIGN(DeterministicMockUDPClientSocket);
 };
@@ -1051,7 +1051,7 @@
   void OnReadComplete(const MockRead& data) override;
   void OnConnectComplete(const MockConnect& data) override;
 
-  void set_source_port(int port) { source_port_ = port;}
+  void set_source_port(uint16 port) { source_port_ = port;}
 
  private:
   int CompleteRead();
@@ -1064,7 +1064,7 @@
   int read_offset_;
   MockRead read_data_;
   bool need_read_data_;
-  int source_port_;  // Ephemeral source port.
+  uint16 source_port_;  // Ephemeral source port.
 
   // Address of the "remote" peer we're connected to.
   IPEndPoint peer_addr_;
diff --git a/net/socket/socks5_client_socket_unittest.cc b/net/socket/socks5_client_socket_unittest.cc
index c474a0b..5bcc146 100644
--- a/net/socket/socks5_client_socket_unittest.cc
+++ b/net/socket/socks5_client_socket_unittest.cc
@@ -258,7 +258,7 @@
     const char partial1[] = { 0x05, 0x01 };
     const char partial2[] = { 0x00 };
     MockWrite data_writes[] = {
-        MockWrite(ASYNC, arraysize(partial1)),
+        MockWrite(ASYNC, partial1, arraysize(partial1)),
         MockWrite(ASYNC, partial2, arraysize(partial2)),
         MockWrite(ASYNC, kOkRequest, arraysize(kOkRequest)) };
     MockRead data_reads[] = {
diff --git a/net/socket/socks_client_socket_unittest.cc b/net/socket/socks_client_socket_unittest.cc
index fbb84f8..01bffe6 100644
--- a/net/socket/socks_client_socket_unittest.cc
+++ b/net/socket/socks_client_socket_unittest.cc
@@ -287,12 +287,12 @@
   const char kSOCKSPartialRequest2[] = { 0x00, 0x50, 127, 0, 0, 1, 0 };
 
   MockWrite data_writes[] = {
-      MockWrite(ASYNC, arraysize(kSOCKSPartialRequest1)),
+      MockWrite(ASYNC, kSOCKSPartialRequest1, arraysize(kSOCKSPartialRequest1)),
       // simulate some empty writes
       MockWrite(ASYNC, 0),
       MockWrite(ASYNC, 0),
-      MockWrite(ASYNC, kSOCKSPartialRequest2,
-                arraysize(kSOCKSPartialRequest2)) };
+      MockWrite(ASYNC, kSOCKSPartialRequest2, arraysize(kSOCKSPartialRequest2)),
+  };
   MockRead data_reads[] = {
       MockRead(ASYNC, kSOCKSOkReply, arraysize(kSOCKSOkReply)) };
   CapturingNetLog log;
diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc
index 57aa619..05eb1cb 100644
--- a/net/socket/ssl_client_socket_openssl.cc
+++ b/net/socket/ssl_client_socket_openssl.cc
@@ -17,6 +17,7 @@
 #include "base/environment.h"
 #include "base/memory/singleton.h"
 #include "base/metrics/histogram.h"
+#include "base/profiler/scoped_tracker.h"
 #include "base/strings/string_piece.h"
 #include "base/synchronization/lock.h"
 #include "crypto/ec_private_key.h"
@@ -899,10 +900,20 @@
 }
 
 int SSLClientSocketOpenSSL::DoHandshake() {
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed.
+  tracked_objects::ScopedTracker tracking_profile1(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "424386 SSLClientSocketOpenSSL::DoHandshake1"));
+
   crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
   int net_error = OK;
   int rv = SSL_do_handshake(ssl_);
 
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed.
+  tracked_objects::ScopedTracker tracking_profile2(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "424386 SSLClientSocketOpenSSL::DoHandshake2"));
+
   if (client_auth_cert_needed_) {
     net_error = ERR_SSL_CLIENT_AUTH_CERT_NEEDED;
     // If the handshake already succeeded (because the server requests but
@@ -1608,6 +1619,11 @@
 }
 
 int SSLClientSocketOpenSSL::ClientCertRequestCallback(SSL* ssl) {
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed.
+  tracked_objects::ScopedTracker tracking_profile(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "424386 SSLClientSocketOpenSSL::ClientCertRequestCallback"));
+
   DVLOG(3) << "OpenSSL ClientCertRequestCallback called";
   DCHECK(ssl == ssl_);
 
@@ -1705,6 +1721,11 @@
 }
 
 int SSLClientSocketOpenSSL::CertVerifyCallback(X509_STORE_CTX* store_ctx) {
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed.
+  tracked_objects::ScopedTracker tracking_profile(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "424386 SSLClientSocketOpenSSL::CertVerifyCallback"));
+
   if (!completed_connect_) {
     // If the first handshake hasn't completed then we accept any certificates
     // because we verify after the handshake.
@@ -1739,6 +1760,11 @@
                                                     unsigned char* outlen,
                                                     const unsigned char* in,
                                                     unsigned int inlen) {
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed.
+  tracked_objects::ScopedTracker tracking_profile(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "424386 SSLClientSocketOpenSSL::SelectNextProtoCallback"));
+
   if (ssl_config_.next_protos.empty()) {
     *out = reinterpret_cast<uint8*>(
         const_cast<char*>(kDefaultSupportedNPNProtocol));
diff --git a/net/socket/ssl_client_socket_pool_unittest.cc b/net/socket/ssl_client_socket_pool_unittest.cc
index 8ac29ef..23bb111 100644
--- a/net/socket/ssl_client_socket_pool_unittest.cc
+++ b/net/socket/ssl_client_socket_pool_unittest.cc
@@ -239,8 +239,7 @@
 INSTANTIATE_TEST_CASE_P(
     NextProto,
     SSLClientSocketPoolTest,
-    testing::Values(kProtoDeprecatedSPDY2,
-                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
+    testing::Values(kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
 
 // Tests that the final socket will connect even if all sockets
 // prior to it fail.
diff --git a/net/socket/tcp_listen_socket.cc b/net/socket/tcp_listen_socket.cc
index 585c412..11b2390 100644
--- a/net/socket/tcp_listen_socket.cc
+++ b/net/socket/tcp_listen_socket.cc
@@ -31,7 +31,9 @@
 
 // static
 scoped_ptr<TCPListenSocket> TCPListenSocket::CreateAndListen(
-    const string& ip, int port, StreamListenSocket::Delegate* del) {
+    const string& ip,
+    uint16 port,
+    StreamListenSocket::Delegate* del) {
   SocketDescriptor s = CreateAndBind(ip, port);
   if (s == kInvalidSocket)
     return scoped_ptr<TCPListenSocket>();
@@ -47,7 +49,7 @@
 
 TCPListenSocket::~TCPListenSocket() {}
 
-SocketDescriptor TCPListenSocket::CreateAndBind(const string& ip, int port) {
+SocketDescriptor TCPListenSocket::CreateAndBind(const string& ip, uint16 port) {
   SocketDescriptor s = CreatePlatformSocket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
   if (s != kInvalidSocket) {
 #if defined(OS_POSIX)
@@ -74,7 +76,7 @@
 }
 
 SocketDescriptor TCPListenSocket::CreateAndBindAnyPort(const string& ip,
-                                                       int* port) {
+                                                       uint16* port) {
   SocketDescriptor s = CreateAndBind(ip, 0);
   if (s == kInvalidSocket)
     return kInvalidSocket;
@@ -110,16 +112,4 @@
   socket_delegate_->DidAccept(this, sock.Pass());
 }
 
-TCPListenSocketFactory::TCPListenSocketFactory(const string& ip, int port)
-    : ip_(ip),
-      port_(port) {
-}
-
-TCPListenSocketFactory::~TCPListenSocketFactory() {}
-
-scoped_ptr<StreamListenSocket> TCPListenSocketFactory::CreateAndListen(
-    StreamListenSocket::Delegate* delegate) const {
-  return TCPListenSocket::CreateAndListen(ip_, port_, delegate);
-}
-
 }  // namespace net
diff --git a/net/socket/tcp_listen_socket.h b/net/socket/tcp_listen_socket.h
index 1702e50..01a08a1 100644
--- a/net/socket/tcp_listen_socket.h
+++ b/net/socket/tcp_listen_socket.h
@@ -21,14 +21,16 @@
   // Listen on port for the specified IP address.  Use 127.0.0.1 to only
   // accept local connections.
   static scoped_ptr<TCPListenSocket> CreateAndListen(
-      const std::string& ip, int port, StreamListenSocket::Delegate* del);
+      const std::string& ip,
+      uint16 port,
+      StreamListenSocket::Delegate* del);
 
   // Get raw TCP socket descriptor bound to ip:port.
-  static SocketDescriptor CreateAndBind(const std::string& ip, int port);
+  static SocketDescriptor CreateAndBind(const std::string& ip, uint16 port);
 
   // Get raw TCP socket descriptor bound to ip and return port it is bound to.
   static SocketDescriptor CreateAndBindAnyPort(const std::string& ip,
-                                               int* port);
+                                               uint16* port);
 
  protected:
   TCPListenSocket(SocketDescriptor s, StreamListenSocket::Delegate* del);
@@ -40,23 +42,6 @@
   DISALLOW_COPY_AND_ASSIGN(TCPListenSocket);
 };
 
-// Factory that can be used to instantiate TCPListenSocket.
-class NET_EXPORT TCPListenSocketFactory : public StreamListenSocketFactory {
- public:
-  TCPListenSocketFactory(const std::string& ip, int port);
-  ~TCPListenSocketFactory() override;
-
-  // StreamListenSocketFactory overrides.
-  scoped_ptr<StreamListenSocket> CreateAndListen(
-      StreamListenSocket::Delegate* delegate) const override;
-
- private:
-  const std::string ip_;
-  const int port_;
-
-  DISALLOW_COPY_AND_ASSIGN(TCPListenSocketFactory);
-};
-
 }  // namespace net
 
 #endif  // NET_SOCKET_TCP_LISTEN_SOCKET_H_
diff --git a/net/socket/tcp_server_socket_unittest.cc b/net/socket/tcp_server_socket_unittest.cc
index 01bae9f..2f6491b 100644
--- a/net/socket/tcp_server_socket_unittest.cc
+++ b/net/socket/tcp_server_socket_unittest.cc
@@ -50,7 +50,7 @@
     *success = true;
   }
 
-  void ParseAddress(std::string ip_str, int port, IPEndPoint* address) {
+  void ParseAddress(std::string ip_str, uint16 port, IPEndPoint* address) {
     IPAddressNumber ip_number;
     bool rv = ParseIPLiteralToNumber(ip_str, &ip_number);
     if (!rv)
diff --git a/net/socket/tcp_socket_unittest.cc b/net/socket/tcp_socket_unittest.cc
index 1981388..4bfc138 100644
--- a/net/socket/tcp_socket_unittest.cc
+++ b/net/socket/tcp_socket_unittest.cc
@@ -9,6 +9,7 @@
 #include <string>
 #include <vector>
 
+#include "base/basictypes.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "net/base/address_list.h"
@@ -56,7 +57,9 @@
     *success = true;
   }
 
-  void ParseAddress(const std::string& ip_str, int port, IPEndPoint* address) {
+  void ParseAddress(const std::string& ip_str,
+                    uint16 port,
+                    IPEndPoint* address) {
     IPAddressNumber ip_number;
     bool rv = ParseIPLiteralToNumber(ip_str, &ip_number);
     if (!rv)
diff --git a/net/socket/transport_client_socket_unittest.cc b/net/socket/transport_client_socket_unittest.cc
index d01cbad..e4e060a 100644
--- a/net/socket/transport_client_socket_unittest.cc
+++ b/net/socket/transport_client_socket_unittest.cc
@@ -89,7 +89,7 @@
   }
 
  protected:
-  int listen_port_;
+  uint16 listen_port_;
   CapturingNetLog net_log_;
   ClientSocketFactory* const socket_factory_;
   scoped_ptr<StreamSocket> sock_;
@@ -105,10 +105,10 @@
 
   // Find a free port to listen on
   scoped_ptr<TCPListenSocket> sock;
-  int port;
+  uint16 port;
   // Range of ports to listen on.  Shouldn't need to try many.
-  const int kMinPort = 10100;
-  const int kMaxPort = 10200;
+  const uint16 kMinPort = 10100;
+  const uint16 kMaxPort = 10200;
 #if defined(OS_WIN)
   EnsureWinsockInit();
 #endif
diff --git a/net/socket/unix_domain_server_socket_posix.cc b/net/socket/unix_domain_server_socket_posix.cc
index 4d63283..6866d36 100644
--- a/net/socket/unix_domain_server_socket_posix.cc
+++ b/net/socket/unix_domain_server_socket_posix.cc
@@ -67,7 +67,7 @@
 
 int UnixDomainServerSocket::ListenWithAddressAndPort(
     const std::string& unix_domain_path,
-    int port_unused,
+    uint16 port_unused,
     int backlog) {
   DCHECK(!listen_socket_);
 
diff --git a/net/socket/unix_domain_server_socket_posix.h b/net/socket/unix_domain_server_socket_posix.h
index 0a26eb3..1097548 100644
--- a/net/socket/unix_domain_server_socket_posix.h
+++ b/net/socket/unix_domain_server_socket_posix.h
@@ -53,7 +53,7 @@
   // ServerSocket implementation.
   int Listen(const IPEndPoint& address, int backlog) override;
   int ListenWithAddressAndPort(const std::string& unix_domain_path,
-                               int port_unused,
+                               uint16 port_unused,
                                int backlog) override;
   int GetLocalAddress(IPEndPoint* address) const override;
   int Accept(scoped_ptr<StreamSocket>* socket,
diff --git a/net/spdy/buffered_spdy_framer_unittest.cc b/net/spdy/buffered_spdy_framer_unittest.cc
index 11f8d08..5304f08 100644
--- a/net/spdy/buffered_spdy_framer_unittest.cc
+++ b/net/spdy/buffered_spdy_framer_unittest.cc
@@ -208,8 +208,7 @@
 INSTANTIATE_TEST_CASE_P(
     NextProto,
     BufferedSpdyFramerTest,
-    testing::Values(kProtoDeprecatedSPDY2,
-                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
+    testing::Values(kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
 
 TEST_P(BufferedSpdyFramerTest, OnSetting) {
   SpdyFramer framer(spdy_version());
diff --git a/net/spdy/hpack_huffman_aggregator.cc b/net/spdy/hpack_huffman_aggregator.cc
index 41a3f48..8080a9b 100644
--- a/net/spdy/hpack_huffman_aggregator.cc
+++ b/net/spdy/hpack_huffman_aggregator.cc
@@ -49,10 +49,8 @@
   if (IsCrossOrigin(request)) {
     return;
   }
-  HostPortPair endpoint = HostPortPair(request.url.HostNoBrackets(),
-                                       request.url.EffectiveIntPort());
-  HpackEncoder* encoder = ObtainEncoder(
-      SpdySessionKey(endpoint, proxy, request.privacy_mode));
+  HpackEncoder* encoder = ObtainEncoder(SpdySessionKey(
+      HostPortPair::FromURL(request.url), proxy, request.privacy_mode));
 
   // Convert and encode the request and response header sets.
   {
@@ -108,8 +106,6 @@
 bool HpackHuffmanAggregator::IsCrossOrigin(const HttpRequestInfo& request) {
   // Require that the request is top-level, or that it shares
   // an origin with its referer.
-  HostPortPair endpoint = HostPortPair(request.url.HostNoBrackets(),
-                                       request.url.EffectiveIntPort());
   if ((request.load_flags & LOAD_MAIN_FRAME) == 0) {
     std::string referer_str;
     if (!request.extra_headers.GetHeader(HttpRequestHeaders::kReferer,
@@ -118,9 +114,8 @@
       return true;
     }
     GURL referer(referer_str);
-    HostPortPair referer_endpoint = HostPortPair(referer.HostNoBrackets(),
-                                                 referer.EffectiveIntPort());
-    if (!endpoint.Equals(referer_endpoint)) {
+    if (!HostPortPair::FromURL(request.url).Equals(
+        HostPortPair::FromURL(referer))) {
       // Cross-origin request.
       return true;
     }
diff --git a/net/spdy/spdy_framer.cc b/net/spdy/spdy_framer.cc
index c08b597..f1b1de3 100644
--- a/net/spdy/spdy_framer.cc
+++ b/net/spdy/spdy_framer.cc
@@ -1991,7 +1991,8 @@
       DCHECK(successful_read);
       if (SpdyConstants::IsValidRstStreamStatus(protocol_version(),
                                                 status_raw)) {
-        status = static_cast<SpdyRstStreamStatus>(status_raw);
+        status =
+            SpdyConstants::ParseRstStreamStatus(protocol_version(), status_raw);
       } else {
         if (protocol_version() > SPDY3) {
           // Treat unrecognized status codes as INTERNAL_ERROR as
@@ -2484,7 +2485,8 @@
     builder.BeginNewFrame(*this, RST_STREAM, 0, rst_stream.stream_id());
   }
 
-  builder.WriteUInt32(rst_stream.status());
+  builder.WriteUInt32(SpdyConstants::SerializeRstStreamStatus(
+      protocol_version(), rst_stream.status()));
 
   // In SPDY4 and up, RST_STREAM frames may also specify opaque data.
   if (protocol_version() > SPDY3 && rst_stream.description().size() > 0) {
diff --git a/net/spdy/spdy_framer_test.cc b/net/spdy/spdy_framer_test.cc
index 2b7bc4b..2fac61c 100644
--- a/net/spdy/spdy_framer_test.cc
+++ b/net/spdy/spdy_framer_test.cc
@@ -2474,7 +2474,7 @@
       0x00, 0x00, 0x04, 0x03,
       0x00, 0x7f, 0xff, 0xff,
       0xff, 0x00, 0x00, 0x00,
-      0x06,
+      0x02,
     };
     SpdyRstStreamIR rst_stream(0x7FFFFFFF,
                                RST_STREAM_INTERNAL_ERROR,
diff --git a/net/spdy/spdy_http_stream_unittest.cc b/net/spdy/spdy_http_stream_unittest.cc
index 574b76a..f22b75f 100644
--- a/net/spdy/spdy_http_stream_unittest.cc
+++ b/net/spdy/spdy_http_stream_unittest.cc
@@ -130,8 +130,7 @@
 INSTANTIATE_TEST_CASE_P(
     NextProto,
     SpdyHttpStreamTest,
-    testing::Values(kProtoDeprecatedSPDY2,
-                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
+    testing::Values(kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
 
 // SpdyHttpStream::GetUploadProgress() should still work even before the
 // stream is initialized.
@@ -700,9 +699,6 @@
 // Test the receipt of a WINDOW_UPDATE frame while waiting for a chunk to be
 // made available is handled correctly.
 TEST_P(SpdyHttpStreamTest, DelayedSendChunkedPostWithWindowUpdate) {
-  if (GetParam() < kProtoSPDY3)
-    return;
-
   scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0));
   scoped_ptr<SpdyFrame> chunk1(spdy_util_.ConstructSpdyBodyFrame(1, true));
   MockWrite writes[] = {
diff --git a/net/spdy/spdy_http_utils.cc b/net/spdy/spdy_http_utils.cc
index b67e699..fc77f5d 100644
--- a/net/spdy/spdy_http_utils.cc
+++ b/net/spdy/spdy_http_utils.cc
@@ -170,42 +170,21 @@
     SpdyMajorVersion protocol_version) {
   DCHECK_GE(priority, MINIMUM_PRIORITY);
   DCHECK_LE(priority, MAXIMUM_PRIORITY);
-  if (protocol_version == SPDY2) {
-    // SPDY 2 only has 2 bits of priority, but we have 5 RequestPriorities.
-    // Map IDLE => 3, LOWEST => 2, LOW => 2, MEDIUM => 1, HIGHEST => 0.
-    if (priority > LOWEST) {
-      return static_cast<SpdyPriority>(HIGHEST - priority);
-    } else {
-      return static_cast<SpdyPriority>(HIGHEST - priority - 1);
-    }
-  } else {
-    return static_cast<SpdyPriority>(HIGHEST - priority);
-  }
+  return static_cast<SpdyPriority>(MAXIMUM_PRIORITY - priority);
 }
 
 NET_EXPORT_PRIVATE RequestPriority ConvertSpdyPriorityToRequestPriority(
     SpdyPriority priority,
     SpdyMajorVersion protocol_version) {
-  // Handle invalid values gracefully, and pick LOW to map 2 back
-  // to for SPDY/2.
-  SpdyPriority idle_cutoff = (protocol_version == SPDY2) ? 3 : 5;
-  return (priority >= idle_cutoff) ?
-      IDLE : static_cast<RequestPriority>(HIGHEST - priority);
+  // Handle invalid values gracefully.
+  // Note that SpdyPriority is not an enum, hence the magic constants.
+  return (priority >= 5) ?
+      IDLE : static_cast<RequestPriority>(4 - priority);
 }
 
 GURL GetUrlFromHeaderBlock(const SpdyHeaderBlock& headers,
                            SpdyMajorVersion protocol_version,
                            bool pushed) {
-  // SPDY 2 server push urls are specified in a single "url" header.
-  if (pushed && protocol_version == SPDY2) {
-      std::string url;
-      SpdyHeaderBlock::const_iterator it;
-      it = headers.find("url");
-      if (it != headers.end())
-        url = it->second;
-      return GURL(url);
-  }
-
   const char* scheme_header = protocol_version >= SPDY3 ? ":scheme" : "scheme";
   const char* host_header = protocol_version >= SPDY4 ? ":authority" :
       (protocol_version >= SPDY3 ? ":host" : "host");
diff --git a/net/spdy/spdy_http_utils_unittest.cc b/net/spdy/spdy_http_utils_unittest.cc
index d811164..b66534b 100644
--- a/net/spdy/spdy_http_utils_unittest.cc
+++ b/net/spdy/spdy_http_utils_unittest.cc
@@ -11,14 +11,6 @@
 
 namespace {
 
-TEST(SpdyHttpUtilsTest, ConvertRequestPriorityToSpdy2Priority) {
-  EXPECT_EQ(0, ConvertRequestPriorityToSpdyPriority(HIGHEST, SPDY2));
-  EXPECT_EQ(1, ConvertRequestPriorityToSpdyPriority(MEDIUM, SPDY2));
-  EXPECT_EQ(2, ConvertRequestPriorityToSpdyPriority(LOW, SPDY2));
-  EXPECT_EQ(2, ConvertRequestPriorityToSpdyPriority(LOWEST, SPDY2));
-  EXPECT_EQ(3, ConvertRequestPriorityToSpdyPriority(IDLE, SPDY2));
-}
-
 TEST(SpdyHttpUtilsTest, ConvertRequestPriorityToSpdy3Priority) {
   EXPECT_EQ(0, ConvertRequestPriorityToSpdyPriority(HIGHEST, SPDY3));
   EXPECT_EQ(1, ConvertRequestPriorityToSpdyPriority(MEDIUM, SPDY3));
@@ -27,18 +19,6 @@
   EXPECT_EQ(4, ConvertRequestPriorityToSpdyPriority(IDLE, SPDY3));
 }
 
-TEST(SpdyHttpUtilsTest, ConvertSpdy2PriorityToRequestPriority) {
-  EXPECT_EQ(HIGHEST, ConvertSpdyPriorityToRequestPriority(0, SPDY2));
-  EXPECT_EQ(MEDIUM, ConvertSpdyPriorityToRequestPriority(1, SPDY2));
-  EXPECT_EQ(LOW, ConvertSpdyPriorityToRequestPriority(2, SPDY2));
-  EXPECT_EQ(IDLE, ConvertSpdyPriorityToRequestPriority(3, SPDY2));
-  // These are invalid values, but we should still handle them
-  // gracefully.
-  for (int i = 4; i < kuint8max; ++i) {
-    EXPECT_EQ(IDLE, ConvertSpdyPriorityToRequestPriority(i, SPDY2));
-  }
-}
-
 TEST(SpdyHttpUtilsTest, ConvertSpdy3PriorityToRequestPriority) {
   EXPECT_EQ(HIGHEST, ConvertSpdyPriorityToRequestPriority(0, SPDY3));
   EXPECT_EQ(MEDIUM, ConvertSpdyPriorityToRequestPriority(1, SPDY3));
diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc
index edb39e9..3836fd3 100644
--- a/net/spdy/spdy_network_transaction_unittest.cc
+++ b/net/spdy/spdy_network_transaction_unittest.cc
@@ -58,7 +58,7 @@
 
 struct SpdyNetworkTransactionTestParams {
   SpdyNetworkTransactionTestParams()
-      : protocol(kProtoSPDY3),
+      : protocol(kProtoSPDY31),
         ssl_type(SPDYNPN) {}
 
   SpdyNetworkTransactionTestParams(
@@ -717,12 +717,6 @@
     Spdy,
     SpdyNetworkTransactionTest,
     ::testing::Values(
-        SpdyNetworkTransactionTestParams(kProtoDeprecatedSPDY2, SPDYNOSSL),
-        SpdyNetworkTransactionTestParams(kProtoDeprecatedSPDY2, SPDYSSL),
-        SpdyNetworkTransactionTestParams(kProtoDeprecatedSPDY2, SPDYNPN),
-        SpdyNetworkTransactionTestParams(kProtoSPDY3, SPDYNOSSL),
-        SpdyNetworkTransactionTestParams(kProtoSPDY3, SPDYSSL),
-        SpdyNetworkTransactionTestParams(kProtoSPDY3, SPDYNPN),
         SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYNOSSL),
         SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYSSL),
         SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYNPN),
@@ -5843,9 +5837,6 @@
 // limitations as described above and it's not deterministic, tests may
 // fail under specific circumstances.
 TEST_P(SpdyNetworkTransactionTest, WindowUpdateReceived) {
-  if (GetParam().protocol < kProtoSPDY3)
-    return;
-
   static int kFrameCount = 2;
   scoped_ptr<std::string> content(
       new std::string(kMaxSpdyFrameChunkSize, 'a'));
@@ -5934,9 +5925,6 @@
 // Test that received data frames and sent WINDOW_UPDATE frames change
 // the recv_window_size_ correctly.
 TEST_P(SpdyNetworkTransactionTest, WindowUpdateSent) {
-  if (GetParam().protocol < kProtoSPDY3)
-    return;
-
   // Amount of body required to trigger a sent window update.
   const size_t kTargetSize = kSpdyStreamInitialWindowSize / 2 + 1;
 
@@ -6016,9 +6004,6 @@
 
 // Test that WINDOW_UPDATE frame causing overflow is handled correctly.
 TEST_P(SpdyNetworkTransactionTest, WindowUpdateOverflow) {
-  if (GetParam().protocol < kProtoSPDY3)
-    return;
-
   // Number of full frames we hope to write (but will not, used to
   // set content-length header correctly)
   static int kFrameCount = 3;
@@ -6098,9 +6083,6 @@
 // After that, next read is artifically enforced, which causes a
 // WINDOW_UPDATE to be read and I/O process resumes.
 TEST_P(SpdyNetworkTransactionTest, FlowControlStallResume) {
-  if (GetParam().protocol < kProtoSPDY3)
-    return;
-
   // Number of frames we need to send to zero out the window size: data
   // frames plus SYN_STREAM plus the last data frame; also we need another
   // data frame that we will send once the WINDOW_UPDATE is received,
@@ -6212,9 +6194,6 @@
 // Test we correctly handle the case where the SETTINGS frame results in
 // unstalling the send window.
 TEST_P(SpdyNetworkTransactionTest, FlowControlStallResumeAfterSettings) {
-  if (GetParam().protocol < kProtoSPDY3)
-    return;
-
   // Number of frames we need to send to zero out the window size: data
   // frames plus SYN_STREAM plus the last data frame; also we need another
   // data frame that we will send once the SETTING is received, therefore +3.
@@ -6333,9 +6312,6 @@
 // Test we correctly handle the case where the SETTINGS frame results in a
 // negative send window size.
 TEST_P(SpdyNetworkTransactionTest, FlowControlNegativeSendWindowSize) {
-  if (GetParam().protocol < kProtoSPDY3)
-    return;
-
   // Number of frames we need to send to zero out the window size: data
   // frames plus SYN_STREAM plus the last data frame; also we need another
   // data frame that we will send once the SETTING is received, therefore +3.
@@ -6390,10 +6366,7 @@
       spdy_util_.ConstructSpdyWindowUpdate(1, kSpdyStreamInitialWindowSize));
 
   reads.push_back(CreateMockRead(*settings_frame_small, i++));
-
-  if (GetParam().protocol >= kProtoSPDY3)
-    reads.push_back(CreateMockRead(*session_window_update_init_size, i++));
-
+  reads.push_back(CreateMockRead(*session_window_update_init_size, i++));
   reads.push_back(CreateMockRead(*window_update_init_size, i++));
 
   scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
@@ -6557,10 +6530,7 @@
 INSTANTIATE_TEST_CASE_P(
     Spdy,
     SpdyNetworkTransactionNoTLSUsageCheckTest,
-    ::testing::Values(SpdyNetworkTransactionTestParams(kProtoDeprecatedSPDY2,
-                                                       SPDYNPN),
-                      SpdyNetworkTransactionTestParams(kProtoSPDY3, SPDYNPN),
-                      SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYNPN)));
+    ::testing::Values(SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYNPN)));
 
 TEST_P(SpdyNetworkTransactionNoTLSUsageCheckTest, TLSVersionTooOld) {
   scoped_ptr<SSLSocketDataProvider> ssl_provider(
diff --git a/net/spdy/spdy_proxy_client_socket_unittest.cc b/net/spdy/spdy_proxy_client_socket_unittest.cc
index ba5d867..a707ef4 100644
--- a/net/spdy/spdy_proxy_client_socket_unittest.cc
+++ b/net/spdy/spdy_proxy_client_socket_unittest.cc
@@ -142,8 +142,7 @@
 INSTANTIATE_TEST_CASE_P(
     NextProto,
     SpdyProxyClientSocketTest,
-    testing::Values(kProtoDeprecatedSPDY2,
-                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
+    testing::Values(kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
 
 SpdyProxyClientSocketTest::SpdyProxyClientSocketTest()
     : spdy_util_(GetParam()),
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc
index 08d838a..1c9abce 100644
--- a/net/spdy/spdy_session.cc
+++ b/net/spdy/spdy_session.cc
@@ -271,6 +271,14 @@
   return dict;
 }
 
+base::Value* NetLogSpdyAdoptedPushStreamCallback(
+    SpdyStreamId stream_id, const GURL* url, NetLog::LogLevel log_level) {
+  base::DictionaryValue* dict = new base::DictionaryValue();
+  dict->SetInteger("stream_id", stream_id);
+  dict->SetString("url", url->spec());
+  return dict;
+}
+
 // Helper function to return the total size of an array of objects
 // with .size() member functions.
 template <typename T, size_t N> size_t GetTotalSize(const T (&arr)[N]) {
@@ -1963,7 +1971,9 @@
     return base::WeakPtr<SpdyStream>();
   }
 
-  net_log_.AddEvent(NetLog::TYPE_SPDY_STREAM_ADOPTED_PUSH_STREAM);
+  net_log_.AddEvent(NetLog::TYPE_SPDY_STREAM_ADOPTED_PUSH_STREAM,
+                    base::Bind(&NetLogSpdyAdoptedPushStreamCallback,
+                               active_it->second.stream->stream_id(), &url));
   used_push_streams.Increment();
   return active_it->second.stream->GetWeakPtr();
 }
diff --git a/net/spdy/spdy_session_pool_unittest.cc b/net/spdy/spdy_session_pool_unittest.cc
index fc38cc2..9d5e48c 100644
--- a/net/spdy/spdy_session_pool_unittest.cc
+++ b/net/spdy/spdy_session_pool_unittest.cc
@@ -51,8 +51,7 @@
 INSTANTIATE_TEST_CASE_P(
     NextProto,
     SpdySessionPoolTest,
-    testing::Values(kProtoDeprecatedSPDY2,
-                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
+    testing::Values(kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
 
 // A delegate that opens a new session when it is closed.
 class SessionOpeningDelegate : public SpdyStream::Delegate {
diff --git a/net/spdy/spdy_session_unittest.cc b/net/spdy/spdy_session_unittest.cc
index 02e0c74..6ec3383 100644
--- a/net/spdy/spdy_session_unittest.cc
+++ b/net/spdy/spdy_session_unittest.cc
@@ -181,8 +181,7 @@
 INSTANTIATE_TEST_CASE_P(
     NextProto,
     SpdySessionTest,
-    testing::Values(kProtoDeprecatedSPDY2,
-                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
+    testing::Values(kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
 
 // Try to create a SPDY session that will fail during
 // initialization. Nothing should blow up.
@@ -1798,10 +1797,6 @@
   data.RunFor(1);
   // Regression test of compression performance under the request fixture.
   switch (spdy_util_.spdy_version()) {
-    case SPDY2:
-      histogram_tester.ExpectBucketCount(
-          "Net.SpdySynStreamCompressionPercentage", 0, 1);
-      break;
     case SPDY3:
       histogram_tester.ExpectBucketCount(
           "Net.SpdySynStreamCompressionPercentage", 30, 1);
@@ -3084,22 +3079,12 @@
 
   EXPECT_EQ(spdy_util_.spdy_version(),
             session->buffered_spdy_framer_->protocol_version());
-  if (GetParam() == kProtoDeprecatedSPDY2) {
-    EXPECT_EQ(SpdySession::FLOW_CONTROL_NONE, session->flow_control_state());
-    EXPECT_EQ(0, session->session_send_window_size_);
-    EXPECT_EQ(0, session->session_recv_window_size_);
-  } else if (GetParam() == kProtoSPDY3) {
-    EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM, session->flow_control_state());
-    EXPECT_EQ(0, session->session_send_window_size_);
-    EXPECT_EQ(0, session->session_recv_window_size_);
-  } else {
-    EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
-              session->flow_control_state());
-    EXPECT_EQ(kSpdySessionInitialWindowSize,
-              session->session_send_window_size_);
-    EXPECT_EQ(kSpdySessionInitialWindowSize,
-              session->session_recv_window_size_);
-  }
+  EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
+            session->flow_control_state());
+  EXPECT_EQ(kSpdySessionInitialWindowSize,
+            session->session_send_window_size_);
+  EXPECT_EQ(kSpdySessionInitialWindowSize,
+            session->session_recv_window_size_);
   EXPECT_EQ(0, session->session_unacked_recv_window_bytes_);
 }
 
@@ -3455,9 +3440,6 @@
 // The tests below are only for SPDY/3 and above.
 
 TEST_P(SpdySessionTest, UpdateStreamsSendWindowSize) {
-  if (GetParam() < kProtoSPDY3)
-    return;
-
   // Set SETTINGS_INITIAL_WINDOW_SIZE to a small number so that WINDOW_UPDATE
   // gets sent.
   SettingsMap new_settings;
diff --git a/net/spdy/spdy_stream_unittest.cc b/net/spdy/spdy_stream_unittest.cc
index 96153bf..e8915bb 100644
--- a/net/spdy/spdy_stream_unittest.cc
+++ b/net/spdy/spdy_stream_unittest.cc
@@ -110,8 +110,7 @@
 INSTANTIATE_TEST_CASE_P(
     NextProto,
     SpdyStreamTest,
-    testing::Values(kProtoDeprecatedSPDY2,
-                    kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
+    testing::Values(kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
 
 TEST_P(SpdyStreamTest, SendDataAfterOpen) {
   GURL url(kStreamUrl);
@@ -717,9 +716,6 @@
 // to overflow an int32. The SpdyStream should handle that case
 // gracefully.
 TEST_P(SpdyStreamTest, IncreaseSendWindowSizeOverflow) {
-  if (spdy_util_.protocol() < kProtoSPDY3)
-    return;
-
   session_ =
       SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
 
@@ -877,17 +873,11 @@
 }
 
 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseRequestResponse) {
-  if (spdy_util_.protocol() < kProtoSPDY3)
-    return;
-
   RunResumeAfterUnstallRequestResponseTest(
       base::Bind(&IncreaseStreamSendWindowSize));
 }
 
 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustRequestResponse) {
-  if (spdy_util_.protocol() < kProtoSPDY3)
-    return;
-
   RunResumeAfterUnstallRequestResponseTest(
       base::Bind(&AdjustStreamSendWindowSize));
 }
@@ -972,17 +962,11 @@
 }
 
 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeIncreaseBidirectional) {
-  if (spdy_util_.protocol() < kProtoSPDY3)
-    return;
-
   RunResumeAfterUnstallBidirectionalTest(
       base::Bind(&IncreaseStreamSendWindowSize));
 }
 
 TEST_P(SpdyStreamTest, ResumeAfterSendWindowSizeAdjustBidirectional) {
-  if (spdy_util_.protocol() < kProtoSPDY3)
-    return;
-
   RunResumeAfterUnstallBidirectionalTest(
       base::Bind(&AdjustStreamSendWindowSize));
 }
diff --git a/net/spdy/spdy_test_util_common.cc b/net/spdy/spdy_test_util_common.cc
index 801d67d..9543e64 100644
--- a/net/spdy/spdy_test_util_common.cc
+++ b/net/spdy/spdy_test_util_common.cc
@@ -54,8 +54,6 @@
 NextProtoVector SpdyNextProtos() {
   NextProtoVector next_protos;
   next_protos.push_back(kProtoHTTP11);
-  next_protos.push_back(kProtoDeprecatedSPDY2);
-  next_protos.push_back(kProtoSPDY3);
   next_protos.push_back(kProtoSPDY31);
   next_protos.push_back(kProtoSPDY4_14);
   next_protos.push_back(kProtoSPDY4_15);
@@ -720,15 +718,11 @@
 
 void SpdyTestUtil::AddUrlToHeaderBlock(base::StringPiece url,
                                        SpdyHeaderBlock* headers) const {
-  if (is_spdy2()) {
-    (*headers)["url"] = url.as_string();
-  } else {
-    std::string scheme, host, path;
-    ParseUrl(url, &scheme, &host, &path);
-    (*headers)[GetSchemeKey()] = scheme;
-    (*headers)[GetHostKey()] = host;
-    (*headers)[GetPathKey()] = path;
-  }
+  std::string scheme, host, path;
+  ParseUrl(url, &scheme, &host, &path);
+  (*headers)[GetSchemeKey()] = scheme;
+  (*headers)[GetHostKey()] = host;
+  (*headers)[GetPathKey()] = path;
 }
 
 scoped_ptr<SpdyHeaderBlock> SpdyTestUtil::ConstructGetHeaderBlock(
@@ -739,8 +733,6 @@
 scoped_ptr<SpdyHeaderBlock> SpdyTestUtil::ConstructGetHeaderBlockForProxy(
     base::StringPiece url) const {
   scoped_ptr<SpdyHeaderBlock> headers(ConstructGetHeaderBlock(url));
-  if (is_spdy2())
-    (*headers)[GetPathKey()] = url.data();
   return headers.Pass();
 }
 
@@ -963,8 +955,7 @@
                                           bool direct) const {
   SpdyHeaderBlock block;
   block[GetMethodKey()] = "GET";
-  block[GetPathKey()] =
-      (is_spdy2() && !direct) ? "http://www.google.com/" : "/";
+  block[GetPathKey()] = "/";
   block[GetHostKey()] = "www.google.com";
   block[GetSchemeKey()] = "http";
   MaybeAddVersionHeader(&block);
@@ -1259,16 +1250,14 @@
 }
 
 const char* SpdyTestUtil::GetMethodKey() const {
-  return is_spdy2() ? "method" : ":method";
+  return ":method";
 }
 
 const char* SpdyTestUtil::GetStatusKey() const {
-  return is_spdy2() ? "status" : ":status";
+  return ":status";
 }
 
 const char* SpdyTestUtil::GetHostKey() const {
-  if (protocol_ < kProtoSPDY3)
-    return "host";
   if (protocol_ < kProtoSPDY4MinimumVersion)
     return ":host";
   else
@@ -1276,15 +1265,15 @@
 }
 
 const char* SpdyTestUtil::GetSchemeKey() const {
-  return is_spdy2() ? "scheme" : ":scheme";
+  return ":scheme";
 }
 
 const char* SpdyTestUtil::GetVersionKey() const {
-  return is_spdy2() ? "version" : ":version";
+  return ":version";
 }
 
 const char* SpdyTestUtil::GetPathKey() const {
-  return is_spdy2() ? "url" : ":path";
+  return ":path";
 }
 
 scoped_ptr<SpdyHeaderBlock> SpdyTestUtil::ConstructHeaderBlock(
diff --git a/net/spdy/spdy_test_util_common.h b/net/spdy/spdy_test_util_common.h
index b08657c..0ee59d4 100644
--- a/net/spdy/spdy_test_util_common.h
+++ b/net/spdy/spdy_test_util_common.h
@@ -551,7 +551,6 @@
 
   NextProto protocol() const { return protocol_; }
   SpdyMajorVersion spdy_version() const { return spdy_version_; }
-  bool is_spdy2() const { return protocol_ < kProtoSPDY3; }
   bool include_version_header() const {
     return protocol_ < kProtoSPDY4MinimumVersion;
   }
diff --git a/net/test/android/javatests/src/org/chromium/net/test/util/TestWebServer.java b/net/test/android/javatests/src/org/chromium/net/test/util/TestWebServer.java
index 66a9bd9..6121a2a 100644
--- a/net/test/android/javatests/src/org/chromium/net/test/util/TestWebServer.java
+++ b/net/test/android/javatests/src/org/chromium/net/test/util/TestWebServer.java
@@ -86,8 +86,8 @@
             mIsRedirect = isRedirect;
             mIsNotFound = isNotFound;
             mResponseData = responseData;
-            mResponseHeaders = responseHeaders == null ?
-                    new ArrayList<Pair<String, String>>() : responseHeaders;
+            mResponseHeaders = responseHeaders == null
+                    ? new ArrayList<Pair<String, String>>() : responseHeaders;
             mResponseAction = responseAction;
         }
     }
@@ -534,30 +534,30 @@
          * single self-generated key. The subject name is "Test Server".
          */
         private static final String SERVER_KEYS_BKS =
-                "AAAAAQAAABQDkebzoP1XwqyWKRCJEpn/t8dqIQAABDkEAAVteWtleQAAARpYl20nAAAAAQAFWC41" +
-                "MDkAAAJNMIICSTCCAbKgAwIBAgIESEfU1jANBgkqhkiG9w0BAQUFADBpMQswCQYDVQQGEwJVUzET" +
-                "MBEGA1UECBMKQ2FsaWZvcm5pYTEMMAoGA1UEBxMDTVRWMQ8wDQYDVQQKEwZHb29nbGUxEDAOBgNV" +
-                "BAsTB0FuZHJvaWQxFDASBgNVBAMTC1Rlc3QgU2VydmVyMB4XDTA4MDYwNTExNTgxNFoXDTA4MDkw" +
-                "MzExNTgxNFowaTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExDDAKBgNVBAcTA01U" +
-                "VjEPMA0GA1UEChMGR29vZ2xlMRAwDgYDVQQLEwdBbmRyb2lkMRQwEgYDVQQDEwtUZXN0IFNlcnZl" +
-                "cjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0LIdKaIr9/vsTq8BZlA3R+NFWRaH4lGsTAQy" +
-                "DPMF9ZqEDOaL6DJuu0colSBBBQ85hQTPa9m9nyJoN3pEi1hgamqOvQIWcXBk+SOpUGRZZFXwniJV" +
-                "zDKU5nE9MYgn2B9AoiH3CSuMz6HRqgVaqtppIe1jhukMc/kHVJvlKRNy9XMCAwEAATANBgkqhkiG" +
-                "9w0BAQUFAAOBgQC7yBmJ9O/eWDGtSH9BH0R3dh2NdST3W9hNZ8hIa8U8klhNHbUCSSktZmZkvbPU" +
-                "hse5LI3dh6RyNDuqDrbYwcqzKbFJaq/jX9kCoeb3vgbQElMRX8D2ID1vRjxwlALFISrtaN4VpWzV" +
-                "yeoHPW4xldeZmoVtjn8zXNzQhLuBqX2MmAAAAqwAAAAUvkUScfw9yCSmALruURNmtBai7kQAAAZx" +
-                "4Jmijxs/l8EBaleaUru6EOPioWkUAEVWCxjM/TxbGHOi2VMsQWqRr/DZ3wsDmtQgw3QTrUK666sR" +
-                "MBnbqdnyCyvM1J2V1xxLXPUeRBmR2CXorYGF9Dye7NkgVdfA+9g9L/0Au6Ugn+2Cj5leoIgkgApN" +
-                "vuEcZegFlNOUPVEs3SlBgUF1BY6OBM0UBHTPwGGxFBBcetcuMRbUnu65vyDG0pslT59qpaR0TMVs" +
-                "P+tcheEzhyjbfM32/vwhnL9dBEgM8qMt0sqF6itNOQU/F4WGkK2Cm2v4CYEyKYw325fEhzTXosck" +
-                "MhbqmcyLab8EPceWF3dweoUT76+jEZx8lV2dapR+CmczQI43tV9btsd1xiBbBHAKvymm9Ep9bPzM" +
-                "J0MQi+OtURL9Lxke/70/MRueqbPeUlOaGvANTmXQD2OnW7PISwJ9lpeLfTG0LcqkoqkbtLKQLYHI" +
-                "rQfV5j0j+wmvmpMxzjN3uvNajLa4zQ8l0Eok9SFaRr2RL0gN8Q2JegfOL4pUiHPsh64WWya2NB7f" +
-                "V+1s65eA5ospXYsShRjo046QhGTmymwXXzdzuxu8IlnTEont6P4+J+GsWk6cldGbl20hctuUKzyx" +
-                "OptjEPOKejV60iDCYGmHbCWAzQ8h5MILV82IclzNViZmzAapeeCnexhpXhWTs+xDEYSKEiG/camt" +
-                "bhmZc3BcyVJrW23PktSfpBQ6D8ZxoMfF0L7V2GQMaUg+3r7ucrx82kpqotjv0xHghNIm95aBr1Qw" +
-                "1gaEjsC/0wGmmBDg1dTDH+F1p9TInzr3EFuYD0YiQ7YlAHq3cPuyGoLXJ5dXYuSBfhDXJSeddUkl" +
-                "k1ufZyOOcskeInQge7jzaRfmKg3U94r+spMEvb0AzDQVOKvjjo1ivxMSgFRZaDb/4qw=";
+                "AAAAAQAAABQDkebzoP1XwqyWKRCJEpn/t8dqIQAABDkEAAVteWtleQAAARpYl20nAAAAAQAFWC41"
+                + "MDkAAAJNMIICSTCCAbKgAwIBAgIESEfU1jANBgkqhkiG9w0BAQUFADBpMQswCQYDVQQGEwJVUzET"
+                + "MBEGA1UECBMKQ2FsaWZvcm5pYTEMMAoGA1UEBxMDTVRWMQ8wDQYDVQQKEwZHb29nbGUxEDAOBgNV"
+                + "BAsTB0FuZHJvaWQxFDASBgNVBAMTC1Rlc3QgU2VydmVyMB4XDTA4MDYwNTExNTgxNFoXDTA4MDkw"
+                + "MzExNTgxNFowaTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExDDAKBgNVBAcTA01U"
+                + "VjEPMA0GA1UEChMGR29vZ2xlMRAwDgYDVQQLEwdBbmRyb2lkMRQwEgYDVQQDEwtUZXN0IFNlcnZl"
+                + "cjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0LIdKaIr9/vsTq8BZlA3R+NFWRaH4lGsTAQy"
+                + "DPMF9ZqEDOaL6DJuu0colSBBBQ85hQTPa9m9nyJoN3pEi1hgamqOvQIWcXBk+SOpUGRZZFXwniJV"
+                + "zDKU5nE9MYgn2B9AoiH3CSuMz6HRqgVaqtppIe1jhukMc/kHVJvlKRNy9XMCAwEAATANBgkqhkiG"
+                + "9w0BAQUFAAOBgQC7yBmJ9O/eWDGtSH9BH0R3dh2NdST3W9hNZ8hIa8U8klhNHbUCSSktZmZkvbPU"
+                + "hse5LI3dh6RyNDuqDrbYwcqzKbFJaq/jX9kCoeb3vgbQElMRX8D2ID1vRjxwlALFISrtaN4VpWzV"
+                + "yeoHPW4xldeZmoVtjn8zXNzQhLuBqX2MmAAAAqwAAAAUvkUScfw9yCSmALruURNmtBai7kQAAAZx"
+                + "4Jmijxs/l8EBaleaUru6EOPioWkUAEVWCxjM/TxbGHOi2VMsQWqRr/DZ3wsDmtQgw3QTrUK666sR"
+                + "MBnbqdnyCyvM1J2V1xxLXPUeRBmR2CXorYGF9Dye7NkgVdfA+9g9L/0Au6Ugn+2Cj5leoIgkgApN"
+                + "vuEcZegFlNOUPVEs3SlBgUF1BY6OBM0UBHTPwGGxFBBcetcuMRbUnu65vyDG0pslT59qpaR0TMVs"
+                + "P+tcheEzhyjbfM32/vwhnL9dBEgM8qMt0sqF6itNOQU/F4WGkK2Cm2v4CYEyKYw325fEhzTXosck"
+                + "MhbqmcyLab8EPceWF3dweoUT76+jEZx8lV2dapR+CmczQI43tV9btsd1xiBbBHAKvymm9Ep9bPzM"
+                + "J0MQi+OtURL9Lxke/70/MRueqbPeUlOaGvANTmXQD2OnW7PISwJ9lpeLfTG0LcqkoqkbtLKQLYHI"
+                + "rQfV5j0j+wmvmpMxzjN3uvNajLa4zQ8l0Eok9SFaRr2RL0gN8Q2JegfOL4pUiHPsh64WWya2NB7f"
+                + "V+1s65eA5ospXYsShRjo046QhGTmymwXXzdzuxu8IlnTEont6P4+J+GsWk6cldGbl20hctuUKzyx"
+                + "OptjEPOKejV60iDCYGmHbCWAzQ8h5MILV82IclzNViZmzAapeeCnexhpXhWTs+xDEYSKEiG/camt"
+                + "bhmZc3BcyVJrW23PktSfpBQ6D8ZxoMfF0L7V2GQMaUg+3r7ucrx82kpqotjv0xHghNIm95aBr1Qw"
+                + "1gaEjsC/0wGmmBDg1dTDH+F1p9TInzr3EFuYD0YiQ7YlAHq3cPuyGoLXJ5dXYuSBfhDXJSeddUkl"
+                + "k1ufZyOOcskeInQge7jzaRfmKg3U94r+spMEvb0AzDQVOKvjjo1ivxMSgFRZaDb/4qw=";
 
         private static final String PASSWORD = "android";
 
diff --git a/net/test/embedded_test_server/embedded_test_server.cc b/net/test/embedded_test_server/embedded_test_server.cc
index 7ac764f..97b5d84 100644
--- a/net/test/embedded_test_server/embedded_test_server.cc
+++ b/net/test/embedded_test_server/embedded_test_server.cc
@@ -115,7 +115,7 @@
 }
 
 EmbeddedTestServer::EmbeddedTestServer()
-    : port_(-1),
+    : port_(0),
       weak_factory_(this) {
   DCHECK(thread_checker_.CalledOnValidThread());
 }
diff --git a/net/test/embedded_test_server/embedded_test_server.h b/net/test/embedded_test_server/embedded_test_server.h
index 24ff8d7..586e1f4 100644
--- a/net/test/embedded_test_server/embedded_test_server.h
+++ b/net/test/embedded_test_server/embedded_test_server.h
@@ -136,7 +136,7 @@
               const std::string& relative_url) const;
 
   // Returns the port number used by the server.
-  int port() const { return port_; }
+  uint16 port() const { return port_; }
 
   // Registers request handler which serves files from |directory|.
   // For instance, a request to "/foo.html" is served by "foo.html" under
@@ -188,7 +188,7 @@
   scoped_ptr<base::Thread> io_thread_;
 
   scoped_ptr<HttpListenSocket> listen_socket_;
-  int port_;
+  uint16 port_;
   GURL base_url_;
 
   // Owns the HttpConnection objects.
diff --git a/net/test/embedded_test_server/embedded_test_server_unittest.cc b/net/test/embedded_test_server/embedded_test_server_unittest.cc
index 28d909e..efa4b0c 100644
--- a/net/test/embedded_test_server/embedded_test_server_unittest.cc
+++ b/net/test/embedded_test_server/embedded_test_server_unittest.cc
@@ -112,12 +112,12 @@
 };
 
 TEST_F(EmbeddedTestServerTest, GetBaseURL) {
-  EXPECT_EQ(base::StringPrintf("http://127.0.0.1:%d/", server_->port()),
+  EXPECT_EQ(base::StringPrintf("http://127.0.0.1:%u/", server_->port()),
                                server_->base_url().spec());
 }
 
 TEST_F(EmbeddedTestServerTest, GetURL) {
-  EXPECT_EQ(base::StringPrintf("http://127.0.0.1:%d/path?query=foo",
+  EXPECT_EQ(base::StringPrintf("http://127.0.0.1:%u/path?query=foo",
                                server_->port()),
             server_->GetURL("/path?query=foo").spec());
 }
diff --git a/net/tools/dump_cache/cache_dumper.cc b/net/tools/dump_cache/cache_dumper.cc
index 0ce46a9..99e3dcd 100644
--- a/net/tools/dump_cache/cache_dumper.cc
+++ b/net/tools/dump_cache/cache_dumper.cc
@@ -45,7 +45,6 @@
 #ifdef WIN32_LARGE_FILENAME_SUPPORT
   // Due to large paths on windows, it can't simply do a
   // CreateDirectory("a/b/c").  Instead, create each subdirectory manually.
-  bool rv = false;
   std::wstring::size_type pos(0);
   std::wstring backslash(L"\\");
 
diff --git a/net/tools/flip_server/spdy_interface_test.cc b/net/tools/flip_server/spdy_interface_test.cc
index 09909e2..d845438 100644
--- a/net/tools/flip_server/spdy_interface_test.cc
+++ b/net/tools/flip_server/spdy_interface_test.cc
@@ -206,8 +206,8 @@
 
 INSTANTIATE_TEST_CASE_P(SpdySMProxyTest,
                         SpdySMProxyTest,
-                        Values(SPDY2, SPDY3, SPDY4));
-INSTANTIATE_TEST_CASE_P(SpdySMServerTest, SpdySMServerTest, Values(SPDY2));
+                        Values(SPDY3, SPDY4));
+INSTANTIATE_TEST_CASE_P(SpdySMServerTest, SpdySMServerTest, Values(SPDY4));
 
 TEST_P(SpdySMProxyTest, InitSMConnection) {
   {
@@ -218,113 +218,7 @@
       NULL, NULL, epoll_server_.get(), -1, "", "", "", false);
 }
 
-TEST_P(SpdySMProxyTest, OnSynStream_SPDY2) {
-  if (GetParam() != SPDY2) {
-    // This test case is for SPDY2.
-    return;
-  }
-  BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
-  scoped_ptr<MockSMInterface> mock_interface(new MockSMInterface);
-  uint32 stream_id = 92;
-  uint32 associated_id = 43;
-  std::string expected = "GET /path HTTP/1.0\r\n"
-      "Host: 127.0.0.1\r\n"
-      "hoge: fuga\r\n\r\n";
-  SpdyHeaderBlock block;
-  block["method"] = "GET";
-  block["url"] = "/path";
-  block["scheme"] = "http";
-  block["version"] = "HTTP/1.0";
-  block["hoge"] = "fuga";
-  StringSaver saver;
-  {
-    InSequence s;
-    EXPECT_CALL(*interface_, FindOrMakeNewSMConnectionInterface(_, _))
-        .WillOnce(Return(mock_interface.get()));
-    EXPECT_CALL(*mock_interface, SetStreamID(stream_id));
-    EXPECT_CALL(*mock_interface, ProcessWriteInput(_, _))
-        .WillOnce(DoAll(SaveArg<0>(&saver.data),
-                        SaveArg<1>(&saver.size),
-                        InvokeWithoutArgs(&saver, &StringSaver::Save),
-                        Return(0)));
-  }
-  visitor->OnSynStream(stream_id, associated_id, 0, false, false, block);
-  ASSERT_EQ(expected, saver.string);
-}
-
-TEST_P(SpdySMProxyTest, OnSynStream) {
-  if (GetParam() == SPDY2) {
-    // This test case is not for SPDY2.
-    return;
-  }
-  BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
-  scoped_ptr<MockSMInterface> mock_interface(new MockSMInterface);
-  uint32 stream_id = 92;
-  uint32 associated_id = 43;
-  std::string expected = "GET /path HTTP/1.1\r\n"
-      "Host: 127.0.0.1\r\n"
-      "foo: bar\r\n\r\n";
-  SpdyHeaderBlock block;
-  block[":method"] = "GET";
-  block[":host"] = "www.example.com";
-  block[":path"] = "/path";
-  block[":scheme"] = "http";
-  block["foo"] = "bar";
-  StringSaver saver;
-  {
-    InSequence s;
-    EXPECT_CALL(*interface_,
-                FindOrMakeNewSMConnectionInterface(_, _))
-        .WillOnce(Return(mock_interface.get()));
-    EXPECT_CALL(*mock_interface, SetStreamID(stream_id));
-    EXPECT_CALL(*mock_interface, ProcessWriteInput(_, _))
-        .WillOnce(DoAll(SaveArg<0>(&saver.data),
-                        SaveArg<1>(&saver.size),
-                        InvokeWithoutArgs(&saver, &StringSaver::Save),
-                        Return(0)));
-  }
-  visitor->OnSynStream(stream_id, associated_id, 0, false, false, block);
-  ASSERT_EQ(expected, saver.string);
-}
-
-TEST_P(SpdySMProxyTest, OnStreamFrameData_SPDY2) {
-  if (GetParam() != SPDY2) {
-    // This test case is for SPDY2.
-    return;
-  }
-  BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
-  scoped_ptr<MockSMInterface> mock_interface(new MockSMInterface);
-  uint32 stream_id = 92;
-  uint32 associated_id = 43;
-  SpdyHeaderBlock block;
-  testing::MockFunction<void(int)> checkpoint;  // NOLINT
-
-  scoped_ptr<SpdyFrame> frame(spdy_framer_->CreatePingFrame(12, false));
-  block["method"] = "GET";
-  block["url"] = "http://www.example.com/path";
-  block["scheme"] = "http";
-  block["version"] = "HTTP/1.0";
-  {
-    InSequence s;
-    EXPECT_CALL(*interface_, FindOrMakeNewSMConnectionInterface(_, _))
-        .WillOnce(Return(mock_interface.get()));
-    EXPECT_CALL(*mock_interface, SetStreamID(stream_id));
-    EXPECT_CALL(*mock_interface, ProcessWriteInput(_, _)).Times(1);
-    EXPECT_CALL(checkpoint, Call(0));
-    EXPECT_CALL(*mock_interface,
-                ProcessWriteInput(frame->data(), frame->size())).Times(1);
-  }
-
-  visitor->OnSynStream(stream_id, associated_id, 0, false, false, block);
-  checkpoint.Call(0);
-  visitor->OnStreamFrameData(stream_id, frame->data(), frame->size(), true);
-}
-
 TEST_P(SpdySMProxyTest, OnStreamFrameData) {
-  if (GetParam() == SPDY2) {
-    // This test case is not for SPDY2.
-    return;
-  }
   BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
   scoped_ptr<MockSMInterface> mock_interface(new MockSMInterface);
   uint32 stream_id = 92;
@@ -407,14 +301,14 @@
 
 TEST_P(SpdySMProxyTest, CreateFramer) {
   interface_->ResetForNewConnection();
-  interface_->CreateFramer(SPDY2);
-  ASSERT_TRUE(interface_->spdy_framer() != NULL);
-  ASSERT_EQ(interface_->spdy_version(), SPDY2);
-
-  interface_->ResetForNewConnection();
   interface_->CreateFramer(SPDY3);
   ASSERT_TRUE(interface_->spdy_framer() != NULL);
   ASSERT_EQ(interface_->spdy_version(), SPDY3);
+
+  interface_->ResetForNewConnection();
+  interface_->CreateFramer(SPDY4);
+  ASSERT_TRUE(interface_->spdy_framer() != NULL);
+  ASSERT_EQ(interface_->spdy_version(), SPDY4);
 }
 
 TEST_P(SpdySMProxyTest, PostAcceptHook) {
@@ -455,61 +349,7 @@
   ASSERT_TRUE(HasStream(stream_id));
 }
 
-TEST_P(SpdySMProxyTest, SendErrorNotFound_SPDY2) {
-  if (GetParam() != SPDY2) {
-    // This test is for SPDY2.
-    return;
-  }
-  uint32 stream_id = 82;
-  SpdyHeaderBlock actual_header_block;
-  const char* actual_data;
-  size_t actual_size;
-  testing::MockFunction<void(int)> checkpoint;  // NOLINT
-
-  interface_->SendErrorNotFound(stream_id);
-
-  ASSERT_EQ(2u, connection_->output_list()->size());
-
-  {
-    InSequence s;
-    if (GetParam() < SPDY4) {
-      EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
-          .WillOnce(SaveArg<2>(&actual_header_block));
-    } else {
-      EXPECT_CALL(*spdy_framer_visitor_,
-                  OnHeaders(stream_id, false, 0, false, _))
-          .WillOnce(SaveArg<4>(&actual_header_block));
-    }
-    EXPECT_CALL(checkpoint, Call(0));
-    EXPECT_CALL(*spdy_framer_visitor_,
-                OnDataFrameHeader(stream_id, _, true));
-    EXPECT_CALL(*spdy_framer_visitor_,
-                OnStreamFrameData(stream_id, _, _, false)).Times(1)
-        .WillOnce(DoAll(SaveArg<1>(&actual_data),
-                        SaveArg<2>(&actual_size)));
-    EXPECT_CALL(*spdy_framer_visitor_,
-                OnStreamFrameData(stream_id, NULL, 0, true)).Times(1);
-  }
-
-  std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
-  DataFrame* df = *i++;
-  spdy_framer_->ProcessInput(df->data, df->size);
-  checkpoint.Call(0);
-  df = *i++;
-  spdy_framer_->ProcessInput(df->data, df->size);
-
-  ASSERT_EQ(2, spdy_framer_->frames_received());
-  ASSERT_EQ(2u, actual_header_block.size());
-  ASSERT_EQ("404 Not Found", actual_header_block["status"]);
-  ASSERT_EQ("HTTP/1.1", actual_header_block["version"]);
-  ASSERT_EQ("wtf?", StringPiece(actual_data, actual_size));
-}
-
 TEST_P(SpdySMProxyTest, SendErrorNotFound) {
-  if (GetParam() == SPDY2) {
-    // This test is not for SPDY2.
-    return;
-  }
   uint32 stream_id = 82;
   SpdyHeaderBlock actual_header_block;
   const char* actual_data;
@@ -556,44 +396,7 @@
   ASSERT_EQ("wtf?", StringPiece(actual_data, actual_size));
 }
 
-TEST_P(SpdySMProxyTest, SendSynStream_SPDY2) {
-  if (GetParam() != SPDY2) {
-    // This test is for SPDY2.
-    return;
-  }
-  uint32 stream_id = 82;
-  BalsaHeaders headers;
-  SpdyHeaderBlock actual_header_block;
-  headers.AppendHeader("key1", "value1");
-  headers.SetRequestFirstlineFromStringPieces("GET", "/path", "HTTP/1.0");
-
-  interface_->SendSynStream(stream_id, headers);
-
-  ASSERT_EQ(1u, connection_->output_list()->size());
-  std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
-  DataFrame* df = *i++;
-
-  {
-    InSequence s;
-    EXPECT_CALL(*spdy_framer_visitor_,
-                OnSynStream(stream_id, 0, _, false, false, _))
-        .WillOnce(SaveArg<5>(&actual_header_block));
-  }
-
-  spdy_framer_->ProcessInput(df->data, df->size);
-  ASSERT_EQ(1, spdy_framer_->frames_received());
-  ASSERT_EQ(4u, actual_header_block.size());
-  ASSERT_EQ("GET", actual_header_block["method"]);
-  ASSERT_EQ("HTTP/1.0", actual_header_block["version"]);
-  ASSERT_EQ("/path", actual_header_block["url"]);
-  ASSERT_EQ("value1", actual_header_block["key1"]);
-}
-
 TEST_P(SpdySMProxyTest, SendSynStream) {
-  if (GetParam() == SPDY2) {
-    // This test is not for SPDY2.
-    return;
-  }
   uint32 stream_id = 82;
   BalsaHeaders headers;
   SpdyHeaderBlock actual_header_block;
@@ -624,48 +427,7 @@
   ASSERT_EQ("value1", actual_header_block["key1"]);
 }
 
-TEST_P(SpdySMProxyTest, SendSynReply_SPDY2) {
-  if (GetParam() != SPDY2) {
-    // This test is for SPDY2.
-    return;
-  }
-  uint32 stream_id = 82;
-  BalsaHeaders headers;
-  SpdyHeaderBlock actual_header_block;
-  headers.AppendHeader("key1", "value1");
-  headers.SetResponseFirstlineFromStringPieces("HTTP/1.1", "200", "OK");
-
-  interface_->SendSynReply(stream_id, headers);
-
-  ASSERT_EQ(1u, connection_->output_list()->size());
-  std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
-  DataFrame* df = *i++;
-
-  {
-    InSequence s;
-    if (GetParam() < SPDY4) {
-      EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
-          .WillOnce(SaveArg<2>(&actual_header_block));
-    } else {
-      EXPECT_CALL(*spdy_framer_visitor_,
-                  OnHeaders(stream_id, false, 0, false, _))
-          .WillOnce(SaveArg<4>(&actual_header_block));
-    }
-  }
-
-  spdy_framer_->ProcessInput(df->data, df->size);
-  ASSERT_EQ(1, spdy_framer_->frames_received());
-  ASSERT_EQ(3u, actual_header_block.size());
-  ASSERT_EQ("200 OK", actual_header_block["status"]);
-  ASSERT_EQ("HTTP/1.1", actual_header_block["version"]);
-  ASSERT_EQ("value1", actual_header_block["key1"]);
-}
-
 TEST_P(SpdySMProxyTest, SendSynReply) {
-  if (GetParam() == SPDY2) {
-    // This test is not for SPDY2.
-    return;
-  }
   uint32 stream_id = 82;
   BalsaHeaders headers;
   SpdyHeaderBlock actual_header_block;
@@ -763,58 +525,6 @@
   ASSERT_EQ("c", StringPiece(actual_data, actual_size));
 }
 
-TEST_P(SpdySMProxyTest, SendEOF_SPDY2) {
-  // This test is for SPDY2.
-  if (GetParam() != SPDY2) {
-    return;
-  }
-
-  uint32 stream_id = 82;
-  // SPDY2 data frame
-  char empty_data_frame[] = {'\0', '\0', '\0', '\x52', '\x1', '\0', '\0', '\0'};
-  MemCacheIter mci;
-  mci.stream_id = stream_id;
-
-  {
-    BalsaHeaders headers;
-    std::string filename = "foobar";
-    memory_cache_->InsertFile(&headers, filename, "");
-    mci.file_data = memory_cache_->GetFileData(filename);
-  }
-
-  interface_->AddToOutputOrder(mci);
-  ASSERT_TRUE(HasStream(stream_id));
-  interface_->SendEOF(stream_id);
-  ASSERT_FALSE(HasStream(stream_id));
-
-  ASSERT_EQ(1u, connection_->output_list()->size());
-  std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
-  DataFrame* df = *i++;
-  ASSERT_EQ(StringPiece(empty_data_frame, sizeof(empty_data_frame)),
-            StringPiece(df->data, df->size));
-}
-
-TEST_P(SpdySMProxyTest, SendEmptyDataFrame_SPDY2) {
-  // This test is for SPDY2.
-  if (GetParam() != SPDY2) {
-    return;
-  }
-
-  uint32 stream_id = 133;
-  SpdyDataFlags flags = DATA_FLAG_NONE;
-  // SPDY2 data frame
-  char expected[] = {'\0', '\0', '\0', '\x85', '\0', '\0', '\0', '\0'};
-
-  interface_->SendDataFrame(stream_id, "hello", 0, flags, true);
-
-  ASSERT_EQ(1u, connection_->output_list()->size());
-  std::list<DataFrame*>::const_iterator i = connection_->output_list()->begin();
-  DataFrame* df = *i++;
-
-  ASSERT_EQ(StringPiece(expected, sizeof(expected)),
-            StringPiece(df->data, df->size));
-}
-
 TEST_P(SpdySMServerTest, OnSynStream) {
   BufferedSpdyFramerVisitorInterface* visitor = interface_.get();
   uint32 stream_id = 82;
diff --git a/net/tools/gdig/gdig.cc b/net/tools/gdig/gdig.cc
index 179ab78..0f8c1fe 100644
--- a/net/tools/gdig/gdig.cc
+++ b/net/tools/gdig/gdig.cc
@@ -6,6 +6,7 @@
 #include <string>
 
 #include "base/at_exit.h"
+#include "base/basictypes.h"
 #include "base/bind.h"
 #include "base/cancelable_callback.h"
 #include "base/command_line.h"
@@ -53,7 +54,7 @@
   if (!net::ParseIPLiteralToNumber(ip, &ip_number))
     return false;
 
-  *ip_end_point = net::IPEndPoint(ip_number, port);
+  *ip_end_point = net::IPEndPoint(ip_number, static_cast<uint16>(port));
   return true;
 }
 
@@ -90,7 +91,7 @@
        ++i) {
     const DnsHostsKey& key = i->first;
     std::string host_name = key.first;
-    output.append(IPEndPoint(i->second, -1).ToStringWithoutPort());
+    output.append(IPEndPoint(i->second, 0).ToStringWithoutPort());
     output.append(" ").append(host_name).append("\n");
   }
   return output;
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc
index 33f30fc..dcc9345 100644
--- a/net/tools/quic/end_to_end_test.cc
+++ b/net/tools/quic/end_to_end_test.cc
@@ -221,7 +221,7 @@
                "HTTP/1.1", "200", "OK", kBarResponseBody);
   }
 
-  virtual ~EndToEndTest() {
+  ~EndToEndTest() override {
     // TODO(rtenneti): port RecycleUnusedPort if needed.
     // RecycleUnusedPort(server_address_.port());
     QuicInMemoryCachePeer::ResetForTests();
diff --git a/net/tools/quic/quic_client_session_test.cc b/net/tools/quic/quic_client_session_test.cc
index 5b5c415..496211f 100644
--- a/net/tools/quic/quic_client_session_test.cc
+++ b/net/tools/quic/quic_client_session_test.cc
@@ -46,6 +46,8 @@
     session_->InitializeSession(
         QuicServerId(kServerHostname, kPort, false, PRIVACY_MODE_DISABLED),
         &crypto_config_);
+    // Advance the time, because timers do not like uninitialized times.
+    connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
   }
 
   void CompleteCryptoHandshake() {
diff --git a/net/tools/quic/quic_server_session.cc b/net/tools/quic/quic_server_session.cc
index 45c1379..9db2365 100644
--- a/net/tools/quic/quic_server_session.cc
+++ b/net/tools/quic/quic_server_session.cc
@@ -38,14 +38,29 @@
 
 void QuicServerSession::OnConfigNegotiated() {
   QuicSession::OnConfigNegotiated();
-  if (!FLAGS_enable_quic_fec ||
-      !config()->HasReceivedConnectionOptions() ||
-      !net::ContainsQuicTag(config()->ReceivedConnectionOptions(), kFHDR)) {
+
+  if (!config()->HasReceivedConnectionOptions()) {
     return;
   }
-  // kFHDR config maps to FEC protection always for headers stream.
-  // TODO(jri): Add crypto stream in addition to headers for kHDR.
-  headers_stream_->set_fec_policy(FEC_PROTECT_ALWAYS);
+
+  // If the client has provided a bandwidth estimate from the same serving
+  // region, then pass it to the sent packet manager in preparation for possible
+  // bandwidth resumption.
+  const CachedNetworkParameters* cached_network_params =
+      crypto_stream_->previous_cached_network_params();
+  if (FLAGS_quic_enable_bandwidth_resumption_experiment &&
+      cached_network_params != nullptr &&
+      ContainsQuicTag(config()->ReceivedConnectionOptions(), kBWRE) &&
+      cached_network_params->serving_region() == serving_region_) {
+    connection()->ResumeConnectionState(*cached_network_params);
+  }
+
+  if (FLAGS_enable_quic_fec &&
+      ContainsQuicTag(config()->ReceivedConnectionOptions(), kFHDR)) {
+    // kFHDR config maps to FEC protection always for headers stream.
+    // TODO(jri): Add crypto stream in addition to headers for kHDR.
+    headers_stream_->set_fec_policy(FEC_PROTECT_ALWAYS);
+  }
 }
 
 void QuicServerSession::OnConnectionClosed(QuicErrorCode error,
diff --git a/net/tools/quic/quic_server_session_test.cc b/net/tools/quic/quic_server_session_test.cc
index 6a17f53..b0ed5d1 100644
--- a/net/tools/quic/quic_server_session_test.cc
+++ b/net/tools/quic/quic_server_session_test.cc
@@ -292,7 +292,7 @@
   explicit MockQuicCryptoServerStream(
       const QuicCryptoServerConfig& crypto_config, QuicSession* session)
       : QuicCryptoServerStream(crypto_config, session) {}
-  virtual ~MockQuicCryptoServerStream() {}
+  ~MockQuicCryptoServerStream() override {}
 
   MOCK_METHOD1(SendServerConfigUpdate,
                void(const CachedNetworkParameters* cached_network_parameters));
@@ -383,6 +383,46 @@
   session_->OnCongestionWindowChange(now);
 }
 
+TEST_P(QuicServerSessionTest, BandwidthResumptionExperiment) {
+  ValueRestore<bool> old_flag(
+      &FLAGS_quic_enable_bandwidth_resumption_experiment, true);
+
+  // Test that if a client provides a CachedNetworkParameters with the same
+  // serving region as the current server, that this data is passed down to the
+  // send algorithm.
+
+  // Client has sent kBWRE connection option to trigger bandwidth resumption.
+  QuicTagVector copt;
+  copt.push_back(kBWRE);
+  QuicConfigPeer::SetReceivedConnectionOptions(session_->config(), copt);
+
+  const string kTestServingRegion = "a serving region";
+  session_->set_serving_region(kTestServingRegion);
+
+  QuicCryptoServerStream* crypto_stream =
+      static_cast<QuicCryptoServerStream*>(
+          QuicSessionPeer::GetCryptoStream(session_.get()));
+
+  // No effect if no CachedNetworkParameters provided.
+  EXPECT_CALL(*connection_, ResumeConnectionState(_)).Times(0);
+  session_->OnConfigNegotiated();
+
+  // No effect if CachedNetworkParameters provided, but different serving
+  // regions.
+  CachedNetworkParameters cached_network_params;
+  cached_network_params.set_bandwidth_estimate_bytes_per_second(1);
+  cached_network_params.set_serving_region("different serving region");
+  crypto_stream->set_previous_cached_network_params(cached_network_params);
+  EXPECT_CALL(*connection_, ResumeConnectionState(_)).Times(0);
+  session_->OnConfigNegotiated();
+
+  // Same serving region results in CachedNetworkParameters being stored.
+  cached_network_params.set_serving_region(kTestServingRegion);
+  crypto_stream->set_previous_cached_network_params(cached_network_params);
+  EXPECT_CALL(*connection_, ResumeConnectionState(_)).Times(1);
+  session_->OnConfigNegotiated();
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace tools
diff --git a/net/tools/quic/quic_spdy_server_stream_test.cc b/net/tools/quic/quic_spdy_server_stream_test.cc
index 4f5484a..8a3600c 100644
--- a/net/tools/quic/quic_spdy_server_stream_test.cc
+++ b/net/tools/quic/quic_spdy_server_stream_test.cc
@@ -97,7 +97,7 @@
     QuicInMemoryCachePeer::ResetForTests();
   }
 
-  virtual void SetUp() override {
+  void SetUp() override {
     QuicInMemoryCache* cache = QuicInMemoryCache::GetInstance();
 
     BalsaHeaders request_headers, response_headers;
diff --git a/net/tools/quic/quic_time_wait_list_manager_test.cc b/net/tools/quic/quic_time_wait_list_manager_test.cc
index 05c3954..4e5d7c3 100644
--- a/net/tools/quic/quic_time_wait_list_manager_test.cc
+++ b/net/tools/quic/quic_time_wait_list_manager_test.cc
@@ -95,9 +95,9 @@
         client_address_(net::test::TestPeerIPAddress(), kTestPort),
         writer_is_blocked_(false) {}
 
-  virtual ~QuicTimeWaitListManagerTest() override {}
+  ~QuicTimeWaitListManagerTest() override {}
 
-  virtual void SetUp() override {
+  void SetUp() override {
     EXPECT_CALL(writer_, IsWriteBlocked())
         .WillRepeatedly(ReturnPointee(&writer_is_blocked_));
     EXPECT_CALL(writer_, IsWriteBlockedDataBuffered())
diff --git a/net/tools/quic/test_tools/mock_quic_dispatcher.h b/net/tools/quic/test_tools/mock_quic_dispatcher.h
index df32ce4..81f1004 100644
--- a/net/tools/quic/test_tools/mock_quic_dispatcher.h
+++ b/net/tools/quic/test_tools/mock_quic_dispatcher.h
@@ -24,7 +24,7 @@
                      PacketWriterFactory* packet_writer_factory,
                      EpollServer* eps);
 
-  virtual ~MockQuicDispatcher();
+  ~MockQuicDispatcher() override;
 
   MOCK_METHOD3(ProcessPacket, void(const IPEndPoint& server_address,
                                    const IPEndPoint& client_address,
diff --git a/net/tools/quic/test_tools/quic_test_utils.h b/net/tools/quic/test_tools/quic_test_utils.h
index 9db9fb5..e1220cb 100644
--- a/net/tools/quic/test_tools/quic_test_utils.h
+++ b/net/tools/quic/test_tools/quic_test_utils.h
@@ -10,6 +10,7 @@
 #include <string>
 
 #include "base/strings/string_piece.h"
+#include "net/quic/crypto/cached_network_parameters.h"
 #include "net/quic/quic_connection.h"
 #include "net/quic/quic_packet_writer.h"
 #include "net/quic/quic_session.h"
@@ -94,6 +95,8 @@
   MOCK_METHOD0(OnCanWrite, void());
   MOCK_CONST_METHOD0(HasPendingWrites, bool());
 
+  MOCK_METHOD1(ResumeConnectionState, void(const CachedNetworkParameters&));
+
   void ReallyProcessUdpPacket(const IPEndPoint& self_address,
                               const IPEndPoint& peer_address,
                               const QuicEncryptedPacket& packet) {
diff --git a/net/udp/udp_socket_unittest.cc b/net/udp/udp_socket_unittest.cc
index 83689c7..8282596 100644
--- a/net/udp/udp_socket_unittest.cc
+++ b/net/udp/udp_socket_unittest.cc
@@ -119,7 +119,7 @@
 };
 
 // Creates and address from an ip/port and returns it in |address|.
-void CreateUDPAddress(std::string ip_str, int port, IPEndPoint* address) {
+void CreateUDPAddress(std::string ip_str, uint16 port, IPEndPoint* address) {
   IPAddressNumber ip_number;
   bool rv = ParseIPLiteralToNumber(ip_str, &ip_number);
   if (!rv)
@@ -128,7 +128,7 @@
 }
 
 TEST_F(UDPSocketTest, Connect) {
-  const int kPort = 9999;
+  const uint16 kPort = 9999;
   std::string simple_message("hello world!");
 
   // Setup the server to listen.
@@ -216,7 +216,7 @@
 #else
 TEST_F(UDPSocketTest, Broadcast) {
 #endif
-  const int kPort = 9999;
+  const uint16 kPort = 9999;
   std::string first_message("first message"), second_message("second message");
 
   IPEndPoint broadcast_address;
@@ -369,8 +369,8 @@
 // not bind the client's reads to only be from that endpoint, and that we need
 // to always use recvfrom() to disambiguate.
 TEST_F(UDPSocketTest, VerifyConnectBindsAddr) {
-  const int kPort1 = 9999;
-  const int kPort2 = 10000;
+  const uint16 kPort1 = 9999;
+  const uint16 kPort2 = 10000;
   std::string simple_message("hello world!");
   std::string foreign_message("BAD MESSAGE TO GET!!");
 
@@ -538,7 +538,7 @@
 #endif  // defined(OS_ANDROID)
 
 TEST_F(UDPSocketTest, MAYBE_JoinMulticastGroup) {
-  const int kPort = 9999;
+  const uint16 kPort = 9999;
   const char* const kGroup = "237.132.100.17";
 
   IPEndPoint bind_address;
@@ -562,7 +562,7 @@
 }
 
 TEST_F(UDPSocketTest, MulticastOptions) {
-  const int kPort = 9999;
+  const uint16 kPort = 9999;
   IPEndPoint bind_address;
   CreateUDPAddress("0.0.0.0", kPort, &bind_address);
 
diff --git a/net/udp/udp_socket_win.cc b/net/udp/udp_socket_win.cc
index 11c731f..7be97e8 100644
--- a/net/udp/udp_socket_win.cc
+++ b/net/udp/udp_socket_win.cc
@@ -6,6 +6,7 @@
 
 #include <mstcpip.h>
 
+#include "base/basictypes.h"
 #include "base/callback.h"
 #include "base/lazy_instance.h"
 #include "base/logging.h"
@@ -808,8 +809,8 @@
   DCHECK(bind_type_ == DatagramSocket::RANDOM_BIND && !rand_int_cb_.is_null());
 
   for (int i = 0; i < kBindRetries; ++i) {
-    int rv = DoBind(IPEndPoint(address,
-                               rand_int_cb_.Run(kPortStart, kPortEnd)));
+    int rv = DoBind(IPEndPoint(
+        address, static_cast<uint16>(rand_int_cb_.Run(kPortStart, kPortEnd))));
     if (rv == OK || rv != ERR_ADDRESS_IN_USE)
       return rv;
   }
diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc
index a2ce07e..c61a14b 100644
--- a/net/url_request/url_request.cc
+++ b/net/url_request/url_request.cc
@@ -650,12 +650,8 @@
 
   response_info_.was_cached = false;
 
-  // If the referrer is secure, but the requested URL is not, the referrer
-  // policy should be something non-default. If you hit this, please file a
-  // bug.
-  if (referrer_policy_ ==
-          CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE &&
-      GURL(referrer_).SchemeIsSecure() && !url().SchemeIsSecure()) {
+  if (GURL(referrer_) != URLRequestJob::ComputeReferrerForRedirect(
+                             referrer_policy_, referrer_, url())) {
     if (!network_delegate_ ||
         !network_delegate_->CancelURLRequestWithPolicyViolatingReferrerHeader(
             *this, url(), GURL(referrer_))) {
diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h
index 6117419..af972bd 100644
--- a/net/url_request/url_request.h
+++ b/net/url_request/url_request.h
@@ -94,14 +94,22 @@
   // referrer header might be cleared, if the protocol changes from HTTPS to
   // HTTP. This is the default behavior of URLRequest, corresponding to
   // CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE. Alternatively, the
-  // referrer policy can be set to never change the referrer header. This
-  // behavior corresponds to NEVER_CLEAR_REFERRER. Embedders will want to use
-  // NEVER_CLEAR_REFERRER when implementing the meta-referrer support
-  // (http://wiki.whatwg.org/wiki/Meta_referrer) and sending requests with a
-  // non-default referrer policy. Only the default referrer policy requires
-  // the referrer to be cleared on transitions from HTTPS to HTTP.
+  // referrer policy can be set to strip the referrer down to an origin upon
+  // cross-origin navigation (ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN), or
+  // never change the referrer header (NEVER_CLEAR_REFERRER). Embedders will
+  // want to use these options when implementing referrer policy support
+  // (https://w3c.github.io/webappsec/specs/referrer-policy/).
+  //
+  // REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN is a slight variant
+  // on CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE: If the request
+  // downgrades from HTTPS to HTTP, the referrer will be cleared. If the request
+  // transitions cross-origin (but does not downgrade), the referrer's
+  // granularity will be reduced (currently stripped down to an origin rather
+  // than a full URL). Same-origin requests will send the full referrer.
   enum ReferrerPolicy {
     CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
+    REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN,
+    ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN,
     NEVER_CLEAR_REFERRER,
   };
 
diff --git a/net/url_request/url_request_context_builder.cc b/net/url_request/url_request_context_builder.cc
index 41420d5..838aa7b 100644
--- a/net/url_request/url_request_context_builder.cc
+++ b/net/url_request/url_request_context_builder.cc
@@ -122,11 +122,6 @@
     return true;
   }
 
-  int OnBeforeSocketStreamConnect(SocketStream* stream,
-                                  const CompletionCallback& callback) override {
-    return OK;
-  }
-
   DISALLOW_COPY_AND_ASSIGN(BasicNetworkDelegate);
 };
 
diff --git a/net/url_request/url_request_data_job.cc b/net/url_request/url_request_data_job.cc
index 879b8ba..e074646 100644
--- a/net/url_request/url_request_data_job.cc
+++ b/net/url_request/url_request_data_job.cc
@@ -6,7 +6,6 @@
 
 #include "net/url_request/url_request_data_job.h"
 
-#include "base/profiler/scoped_tracker.h"
 #include "net/base/data_url.h"
 #include "net/base/net_errors.h"
 #include "net/http/http_response_headers.h"
@@ -53,10 +52,6 @@
                                std::string* charset,
                                std::string* data,
                                const CompletionCallback& callback) const {
-  // TODO(vadimt): Remove ScopedTracker below once crbug.com/422489 is fixed.
-  tracked_objects::ScopedTracker tracking_profile(
-      FROM_HERE_WITH_EXPLICIT_FUNCTION("422489 URLRequestDataJob::GetData"));
-
   // Check if data URL is valid. If not, don't bother to try to extract data.
   // Otherwise, parse the data from the data URL.
   const GURL& url = request_->url();
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
index 33a5088..acf1d07 100644
--- a/net/url_request/url_request_http_job.cc
+++ b/net/url_request/url_request_http_job.cc
@@ -66,17 +66,13 @@
   base::Time GetRequestTime() const override;
   bool IsCachedContent() const override;
   bool IsDownload() const override;
-  bool SdchResponseExpected() const override;
+  SdchManager::DictionarySet* SdchDictionariesAdvertised() const override;
   int64 GetByteReadCount() const override;
   int GetResponseCode() const override;
   const URLRequestContext* GetURLRequestContext() const override;
   void RecordPacketStats(StatisticSelector statistic) const override;
   const BoundNetLog& GetNetLog() const override;
 
-  // Method to allow us to reset filter context for a response that should have
-  // been SDCH encoded when there is an update due to an explicit HTTP header.
-  void ResetSdchResponseToFalse();
-
  private:
   URLRequestHttpJob* job_;
 
@@ -126,13 +122,9 @@
   return (job_->request_info_.load_flags & LOAD_IS_DOWNLOAD) != 0;
 }
 
-void URLRequestHttpJob::HttpFilterContext::ResetSdchResponseToFalse() {
-  DCHECK(job_->sdch_dictionary_advertised_);
-  job_->sdch_dictionary_advertised_ = false;
-}
-
-bool URLRequestHttpJob::HttpFilterContext::SdchResponseExpected() const {
-  return job_->sdch_dictionary_advertised_;
+SdchManager::DictionarySet*
+URLRequestHttpJob::HttpFilterContext::SdchDictionariesAdvertised() const {
+  return job_->dictionaries_advertised_.get();
 }
 
 int64 URLRequestHttpJob::HttpFilterContext::GetByteReadCount() const {
@@ -200,7 +192,6 @@
                      base::Unretained(this))),
       read_in_progress_(false),
       throttling_entry_(NULL),
-      sdch_dictionary_advertised_(false),
       sdch_test_activated_(false),
       sdch_test_control_(false),
       is_cached_content_(false),
@@ -273,7 +264,7 @@
   // plugin could set a referrer although sending the referrer is inhibited.
   request_info_.extra_headers.RemoveHeader(HttpRequestHeaders::kReferer);
 
-  // Our consumer should have made sure that this is a safe referrer.  See for
+  // Our consumer should have made sure that this is a safe referrer. See for
   // instance WebCore::FrameLoader::HideReferrer.
   if (referrer.is_valid()) {
     request_info_.extra_headers.SetHeader(HttpRequestHeaders::kReferer,
@@ -330,6 +321,7 @@
   ProcessStrictTransportSecurityHeader();
   ProcessPublicKeyPinsHeader();
 
+  // Handle the server notification of a new SDCH dictionary.
   SdchManager* sdch_manager(request()->context()->sdch_manager());
   if (sdch_manager) {
     SdchProblemCode rv = sdch_manager->IsInSupportedDomain(request()->url());
@@ -371,6 +363,24 @@
     }
   }
 
+  // Handle the server signalling no SDCH encoding.
+  if (dictionaries_advertised_) {
+    // We are wary of proxies that discard or damage SDCH encoding. If a server
+    // explicitly states that this is not SDCH content, then we can correct our
+    // assumption that this is an SDCH response, and avoid the need to recover
+    // as though the content is corrupted (when we discover it is not SDCH
+    // encoded).
+    std::string sdch_response_status;
+    void* iter = NULL;
+    while (GetResponseHeaders()->EnumerateHeader(&iter, "X-Sdch-Encode",
+                                                 &sdch_response_status)) {
+      if (sdch_response_status == "0") {
+        dictionaries_advertised_.reset();
+        break;
+      }
+    }
+  }
+
   // The HTTP transaction may be restarted several times for the purposes
   // of sending authorization information. Each time it restarts, we get
   // notified of the headers completion so that we can update the cookie store.
@@ -532,34 +542,34 @@
         }
       }
     }
-    std::string avail_dictionaries;
     if (advertise_sdch) {
-      sdch_manager->GetAvailDictionaryList(request_->url(),
-                                           &avail_dictionaries);
+      dictionaries_advertised_ =
+          sdch_manager->GetDictionarySet(request_->url());
+    }
 
-      // The AllowLatencyExperiment() is only true if we've successfully done a
-      // full SDCH compression recently in this browser session for this host.
-      // Note that for this path, there might be no applicable dictionaries,
-      // and hence we can't participate in the experiment.
-      if (!avail_dictionaries.empty() &&
-          sdch_manager->AllowLatencyExperiment(request_->url())) {
-        // We are participating in the test (or control), and hence we'll
-        // eventually record statistics via either SDCH_EXPERIMENT_DECODE or
-        // SDCH_EXPERIMENT_HOLDBACK, and we'll need some packet timing data.
-        packet_timing_enabled_ = true;
-        if (base::RandDouble() < .01) {
-          sdch_test_control_ = true;  // 1% probability.
-          advertise_sdch = false;
-        } else {
-          sdch_test_activated_ = true;
-        }
+    // The AllowLatencyExperiment() is only true if we've successfully done a
+    // full SDCH compression recently in this browser session for this host.
+    // Note that for this path, there might be no applicable dictionaries,
+    // and hence we can't participate in the experiment.
+    if (dictionaries_advertised_ &&
+        sdch_manager->AllowLatencyExperiment(request_->url())) {
+      // We are participating in the test (or control), and hence we'll
+      // eventually record statistics via either SDCH_EXPERIMENT_DECODE or
+      // SDCH_EXPERIMENT_HOLDBACK, and we'll need some packet timing data.
+      packet_timing_enabled_ = true;
+      if (base::RandDouble() < .01) {
+        sdch_test_control_ = true;  // 1% probability.
+        dictionaries_advertised_.reset();
+        advertise_sdch = false;
+      } else {
+        sdch_test_activated_ = true;
       }
     }
 
     // Supply Accept-Encoding headers first so that it is more likely that they
-    // will be in the first transmitted packet.  This can sometimes make it
+    // will be in the first transmitted packet. This can sometimes make it
     // easier to filter and analyze the streams to assure that a proxy has not
-    // damaged these headers.  Some proxies deliberately corrupt Accept-Encoding
+    // damaged these headers. Some proxies deliberately corrupt Accept-Encoding
     // headers.
     if (!advertise_sdch) {
       // Tell the server what compression formats we support (other than SDCH).
@@ -569,15 +579,14 @@
       // Include SDCH in acceptable list.
       request_info_.extra_headers.SetHeader(
           HttpRequestHeaders::kAcceptEncoding, "gzip, deflate, sdch");
-      if (!avail_dictionaries.empty()) {
+      if (dictionaries_advertised_) {
         request_info_.extra_headers.SetHeader(
             kAvailDictionaryHeader,
-            avail_dictionaries);
-        sdch_dictionary_advertised_ = true;
+            dictionaries_advertised_->GetDictionaryClientHashList());
         // Since we're tagging this transaction as advertising a dictionary,
         // we'll definitely employ an SDCH filter (or tentative sdch filter)
-        // when we get a response.  When done, we'll record histograms via
-        // SDCH_DECODE or SDCH_PASSTHROUGH.  Hence we need to record packet
+        // when we get a response. When done, we'll record histograms via
+        // SDCH_DECODE or SDCH_PASSTHROUGH. Hence we need to record packet
         // arrival times.
         packet_timing_enabled_ = true;
       }
@@ -1029,7 +1038,7 @@
 void URLRequestHttpJob::GetLoadTimingInfo(
     LoadTimingInfo* load_timing_info) const {
   // If haven't made it far enough to receive any headers, don't return
-  // anything.  This makes for more consistent behavior in the case of errors.
+  // anything. This makes for more consistent behavior in the case of errors.
   if (!transaction_ || receive_headers_end_.is_null())
     return;
   if (transaction_->GetLoadTimingInfo(load_timing_info))
@@ -1072,23 +1081,6 @@
     encoding_types.push_back(Filter::ConvertEncodingToType(encoding_type));
   }
 
-  if (filter_context_->SdchResponseExpected()) {
-    // We are wary of proxies that discard or damage SDCH encoding.  If a server
-    // explicitly states that this is not SDCH content, then we can correct our
-    // assumption that this is an SDCH response, and avoid the need to recover
-    // as though the content is corrupted (when we discover it is not SDCH
-    // encoded).
-    std::string sdch_response_status;
-    iter = NULL;
-    while (headers->EnumerateHeader(&iter, "X-Sdch-Encode",
-                                    &sdch_response_status)) {
-      if (sdch_response_status == "0") {
-        filter_context_->ResetSdchResponseToFalse();
-        break;
-      }
-    }
-  }
-
   // Even if encoding types are empty, there is a chance that we need to add
   // some decoding, as some proxies strip encoding completely. In such cases,
   // we may need to add (for example) SDCH filtering (when the context suggests
@@ -1132,7 +1124,7 @@
   if (code == -1)
     return false;
 
-  // Check if we need either Proxy or WWW Authentication.  This could happen
+  // Check if we need either Proxy or WWW Authentication. This could happen
   // because we either provided no auth info, or provided incorrect info.
   switch (code) {
     case 407:
@@ -1266,7 +1258,7 @@
 
 bool URLRequestHttpJob::ShouldFixMismatchedContentLength(int rv) const {
   // Some servers send the body compressed, but specify the content length as
-  // the uncompressed size.  Although this violates the HTTP spec we want to
+  // the uncompressed size. Although this violates the HTTP spec we want to
   // support it (as IE and FireFox do), but *only* for an exact match.
   // See http://crbug.com/79694.
   if (rv == net::ERR_CONTENT_LENGTH_MISMATCH ||
@@ -1461,7 +1453,7 @@
       !prefilter_bytes_read())       // Zero-byte responses aren't useful.
     return;
 
-  // Miniature requests aren't really compressible.  Don't count them.
+  // Miniature requests aren't really compressible. Don't count them.
   const int kMinSize = 16;
   if (prefilter_bytes_read() < kMinSize)
     return;
@@ -1478,14 +1470,14 @@
 
   // We want to record how often downloaded resources are compressed.
   // But, we recognize that different protocols may have different
-  // properties.  So, for each request, we'll put it into one of 3
+  // properties. So, for each request, we'll put it into one of 3
   // groups:
   //      a) SSL resources
   //         Proxies cannot tamper with compression headers with SSL.
   //      b) Non-SSL, loaded-via-proxy resources
   //         In this case, we know a proxy might have interfered.
   //      c) Non-SSL, loaded-without-proxy resources
-  //         In this case, we know there was no explicit proxy.  However,
+  //         In this case, we know there was no explicit proxy. However,
   //         it is possible that a transparent proxy was still interfering.
   //
   // For each group, we record the same 3 histograms.
diff --git a/net/url_request/url_request_http_job.h b/net/url_request/url_request_http_job.h
index f4bea7e..3a23e8a 100644
--- a/net/url_request/url_request_http_job.h
+++ b/net/url_request/url_request_http_job.h
@@ -15,6 +15,7 @@
 #include "net/base/auth.h"
 #include "net/base/completion_callback.h"
 #include "net/base/net_export.h"
+#include "net/base/sdch_manager.h"
 #include "net/cookies/cookie_store.h"
 #include "net/filter/filter.h"
 #include "net/http/http_request_info.h"
@@ -32,7 +33,7 @@
 class UploadDataStream;
 class URLRequestContext;
 
-// A URLRequestJob subclass that is built on top of HttpTransaction.  It
+// A URLRequestJob subclass that is built on top of HttpTransaction. It
 // provides an implementation for both HTTP and HTTPS.
 class NET_EXPORT_PRIVATE URLRequestHttpJob : public URLRequestJob {
  public:
@@ -194,17 +195,15 @@
   scoped_ptr<HttpTransaction> transaction_;
 
   // This is used to supervise traffic and enforce exponential
-  // back-off.  May be NULL.
+  // back-off. May be NULL.
   scoped_refptr<URLRequestThrottlerEntryInterface> throttling_entry_;
 
-  // Indicated if an SDCH dictionary was advertised, and hence an SDCH
-  // compressed response is expected.  We use this to help detect (accidental?)
-  // proxy corruption of a response, which sometimes marks SDCH content as
-  // having no content encoding <oops>.
-  bool sdch_dictionary_advertised_;
+  // A handle to the SDCH dictionaries that were advertised in this request.
+  // May be null.
+  scoped_ptr<SdchManager::DictionarySet> dictionaries_advertised_;
 
   // For SDCH latency experiments, when we are able to do SDCH, we may enable
-  // either an SDCH latency test xor a pass through test.  The following bools
+  // either an SDCH latency test xor a pass through test. The following bools
   // indicate what we decided on for this instance.
   bool sdch_test_activated_;  // Advertising a dictionary for sdch.
   bool sdch_test_control_;    // Not even accepting-content sdch.
@@ -219,7 +218,7 @@
   //
   // TODO(jar): improve the quality of the gathered info by gathering most times
   // at a lower point in the network stack, assuring we have actual packet
-  // boundaries, rather than approximations.  Also note that input byte count
+  // boundaries, rather than approximations. Also note that input byte count
   // as gathered here is post-SSL, and post-cache-fetch, and does not reflect
   // true packet arrival times in such cases.
 
diff --git a/net/url_request/url_request_job.cc b/net/url_request/url_request_job.cc
index 5d32c6f..3cd8cf4 100644
--- a/net/url_request/url_request_job.cc
+++ b/net/url_request/url_request_job.cc
@@ -20,7 +20,6 @@
 #include "net/base/network_delegate.h"
 #include "net/filter/filter.h"
 #include "net/http/http_response_headers.h"
-#include "net/url_request/url_request.h"
 
 namespace {
 
@@ -255,6 +254,42 @@
 void URLRequestJob::NotifyURLRequestDestroyed() {
 }
 
+// static
+GURL URLRequestJob::ComputeReferrerForRedirect(
+    URLRequest::ReferrerPolicy policy,
+    const std::string& referrer,
+    const GURL& redirect_destination) {
+  GURL original_referrer(referrer);
+  bool secure_referrer_but_insecure_destination =
+      original_referrer.SchemeIsSecure() &&
+      !redirect_destination.SchemeIsSecure();
+  bool same_origin =
+      original_referrer.GetOrigin() == redirect_destination.GetOrigin();
+  switch (policy) {
+    case URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE:
+      return secure_referrer_but_insecure_destination ? GURL()
+                                                      : original_referrer;
+
+    case URLRequest::REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN:
+      if (same_origin) {
+        return original_referrer;
+      } else if (secure_referrer_but_insecure_destination) {
+        return GURL();
+      } else {
+        return original_referrer.GetOrigin();
+      }
+
+    case URLRequest::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN:
+      return same_origin ? original_referrer : original_referrer.GetOrigin();
+
+    case URLRequest::NEVER_CLEAR_REFERRER:
+      return original_referrer;
+  }
+
+  NOTREACHED();
+  return GURL();
+}
+
 URLRequestJob::~URLRequestJob() {
   base::PowerMonitor* power_monitor = base::PowerMonitor::Get();
   if (power_monitor)
@@ -863,15 +898,11 @@
         request_->first_party_for_cookies();
   }
 
-  // Suppress the referrer if we're redirecting out of https.
-  if (request_->referrer_policy() ==
-          URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE &&
-      GURL(request_->referrer()).SchemeIsSecure() &&
-      !redirect_info.new_url.SchemeIsSecure()) {
-    redirect_info.new_referrer.clear();
-  } else {
-    redirect_info.new_referrer = request_->referrer();
-  }
+  // Alter the referrer if redirecting cross-origin (especially HTTP->HTTPS).
+  redirect_info.new_referrer =
+      ComputeReferrerForRedirect(request_->referrer_policy(),
+                                 request_->referrer(),
+                                 redirect_info.new_url).spec();
 
   return redirect_info;
 }
diff --git a/net/url_request/url_request_job.h b/net/url_request/url_request_job.h
index e824689..ceb71f5 100644
--- a/net/url_request/url_request_job.h
+++ b/net/url_request/url_request_job.h
@@ -20,6 +20,7 @@
 #include "net/base/upload_progress.h"
 #include "net/cookies/canonical_cookie.h"
 #include "net/url_request/redirect_info.h"
+#include "net/url_request/url_request.h"
 #include "url/gurl.h"
 
 namespace net {
@@ -36,7 +37,6 @@
 class NetworkDelegate;
 class SSLCertRequestInfo;
 class SSLInfo;
-class URLRequest;
 class UploadDataStream;
 class URLRequestStatus;
 class X509Certificate;
@@ -227,6 +227,12 @@
   // canceled by an explicit NetworkDelegate::NotifyURLRequestDestroyed() call.
   virtual void NotifyURLRequestDestroyed();
 
+  // Given |policy|, |referrer|, and |redirect_destination|, returns the
+  // referrer URL mandated by |request|'s referrer policy.
+  static GURL ComputeReferrerForRedirect(URLRequest::ReferrerPolicy policy,
+                                         const std::string& referrer,
+                                         const GURL& redirect_destination);
+
  protected:
   friend class base::RefCounted<URLRequestJob>;
   ~URLRequestJob() override;
diff --git a/net/url_request/url_request_job_manager.h b/net/url_request/url_request_job_manager.h
index ca67e56..6329eab 100644
--- a/net/url_request/url_request_job_manager.h
+++ b/net/url_request/url_request_job_manager.h
@@ -10,6 +10,7 @@
 
 #include "base/synchronization/lock.h"
 #include "base/threading/platform_thread.h"
+#include "net/base/net_export.h"
 #include "net/url_request/url_request.h"
 
 template <typename T> struct DefaultSingletonTraits;
@@ -24,7 +25,7 @@
 //   URLRequest is designed to have all consumers on a single thread, and
 //   so no attempt is made to support Interceptor instances being
 //   registered/unregistered or in any way poked on multiple threads.
-class URLRequestJobManager {
+class NET_EXPORT URLRequestJobManager {
  public:
   // Returns the singleton instance.
   static URLRequestJobManager* GetInstance();
diff --git a/net/url_request/url_request_simple_job.cc b/net/url_request/url_request_simple_job.cc
index 55a0f88..060a90e 100644
--- a/net/url_request/url_request_simple_job.cc
+++ b/net/url_request/url_request_simple_job.cc
@@ -47,6 +47,11 @@
 
 bool URLRequestSimpleJob::ReadRawData(IOBuffer* buf, int buf_size,
                                       int* bytes_read) {
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/422489 is fixed.
+  tracked_objects::ScopedTracker tracking_profile(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "422489 URLRequestSimpleJob::ReadRawData"));
+
   DCHECK(bytes_read);
   int remaining = byte_range_.last_byte_position() - data_offset_ + 1;
   if (buf_size > remaining)
diff --git a/net/url_request/url_request_test_util.cc b/net/url_request/url_request_test_util.cc
index 8f70ee7..6be7da3 100644
--- a/net/url_request/url_request_test_util.cc
+++ b/net/url_request/url_request_test_util.cc
@@ -604,12 +604,6 @@
   return can_throttle_requests_;
 }
 
-int TestNetworkDelegate::OnBeforeSocketStreamConnect(
-    SocketStream* socket,
-    const CompletionCallback& callback) {
-  return OK;
-}
-
 bool TestNetworkDelegate::OnCancelURLRequestWithPolicyViolatingReferrerHeader(
     const URLRequest& request,
     const GURL& target_url,
diff --git a/net/url_request/url_request_test_util.h b/net/url_request/url_request_test_util.h
index 1289db7..1c385b2 100644
--- a/net/url_request/url_request_test_util.h
+++ b/net/url_request/url_request_test_util.h
@@ -325,8 +325,6 @@
   bool OnCanAccessFile(const URLRequest& request,
                        const base::FilePath& path) const override;
   bool OnCanThrottleRequest(const URLRequest& request) const override;
-  int OnBeforeSocketStreamConnect(SocketStream* stream,
-                                  const CompletionCallback& callback) override;
   bool OnCancelURLRequestWithPolicyViolatingReferrerHeader(
       const URLRequest& request,
       const GURL& target_url,
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index 1d777dc..9892a69 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -3913,32 +3913,6 @@
   }
 }
 
-TEST_F(URLRequestTestHTTP, HTTPSToHTTPRedirectNoRefererTest) {
-  ASSERT_TRUE(test_server_.Start());
-
-  SpawnedTestServer https_test_server(
-      SpawnedTestServer::TYPE_HTTPS, SpawnedTestServer::kLocalhost,
-      base::FilePath(FILE_PATH_LITERAL("net/data/ssl")));
-  ASSERT_TRUE(https_test_server.Start());
-
-  // An https server is sent a request with an https referer,
-  // and responds with a redirect to an http url. The http
-  // server should not be sent the referer.
-  GURL http_destination = test_server_.GetURL(std::string());
-  TestDelegate d;
-  scoped_ptr<URLRequest> req(default_context_.CreateRequest(
-      https_test_server.GetURL("server-redirect?" + http_destination.spec()),
-      DEFAULT_PRIORITY, &d, NULL));
-  req->SetReferrer("https://www.referrer.com/");
-  req->Start();
-  base::RunLoop().Run();
-
-  EXPECT_EQ(1, d.response_started_count());
-  EXPECT_EQ(1, d.received_redirect_count());
-  EXPECT_EQ(http_destination, req->url());
-  EXPECT_EQ(std::string(), req->referrer());
-}
-
 TEST_F(URLRequestTestHTTP, RedirectLoadTiming) {
   ASSERT_TRUE(test_server_.Start());
 
@@ -6727,6 +6701,219 @@
   EXPECT_EQ(2, default_network_delegate()->headers_received_count());
 }
 
+class URLRequestTestReferrerPolicy : public URLRequestTest {
+ public:
+  URLRequestTestReferrerPolicy() {}
+
+  void InstantiateSameOriginServers(SpawnedTestServer::Type origin_type) {
+    origin_server_.reset(new SpawnedTestServer(
+        origin_type, SpawnedTestServer::kLocalhost,
+        origin_type == SpawnedTestServer::TYPE_HTTPS
+            ? base::FilePath(FILE_PATH_LITERAL("net/data/ssl"))
+            : base::FilePath(
+                  FILE_PATH_LITERAL("net/data/url_request_unittest"))));
+    ASSERT_TRUE(origin_server_->Start());
+  }
+
+  void InstantiateCrossOriginServers(SpawnedTestServer::Type origin_type,
+                                     SpawnedTestServer::Type destination_type) {
+    origin_server_.reset(new SpawnedTestServer(
+        origin_type, SpawnedTestServer::kLocalhost,
+        origin_type == SpawnedTestServer::TYPE_HTTPS
+            ? base::FilePath(FILE_PATH_LITERAL("net/data/ssl"))
+            : base::FilePath(
+                  FILE_PATH_LITERAL("net/data/url_request_unittest"))));
+    ASSERT_TRUE(origin_server_->Start());
+
+    destination_server_.reset(new SpawnedTestServer(
+        destination_type, SpawnedTestServer::kLocalhost,
+        destination_type == SpawnedTestServer::TYPE_HTTPS
+            ? base::FilePath(FILE_PATH_LITERAL("net/data/ssl"))
+            : base::FilePath(
+                  FILE_PATH_LITERAL("net/data/url_request_unittest"))));
+    ASSERT_TRUE(destination_server_->Start());
+  }
+
+  void VerifyReferrerAfterRedirect(URLRequest::ReferrerPolicy policy,
+                                   const GURL& referrer,
+                                   const GURL& expected) {
+    // Create and execute the request: we'll only have a |destination_server_|
+    // if the origins are meant to be distinct. Otherwise, we'll use the
+    // |origin_server_| for both endpoints.
+    GURL destination_url =
+        destination_server_ ? destination_server_->GetURL("echoheader?Referer")
+                            : origin_server_->GetURL("echoheader?Referer");
+    GURL origin_url =
+        origin_server_->GetURL("server-redirect?" + destination_url.spec());
+
+    TestDelegate d;
+    scoped_ptr<URLRequest> req(
+        default_context_.CreateRequest(origin_url, DEFAULT_PRIORITY, &d, NULL));
+    req->set_referrer_policy(policy);
+    req->SetReferrer(referrer.spec());
+    req->Start();
+    base::RunLoop().Run();
+
+    EXPECT_EQ(1, d.response_started_count());
+    EXPECT_EQ(1, d.received_redirect_count());
+    EXPECT_EQ(destination_url, req->url());
+    EXPECT_TRUE(req->status().is_success());
+    EXPECT_EQ(200, req->response_headers()->response_code());
+
+    EXPECT_EQ(expected.spec(), req->referrer());
+    if (expected.is_empty())
+      EXPECT_EQ("None", d.data_received());
+    else
+      EXPECT_EQ(expected.spec(), d.data_received());
+  }
+
+  SpawnedTestServer* origin_server() const { return origin_server_.get(); }
+
+ private:
+  scoped_ptr<SpawnedTestServer> origin_server_;
+  scoped_ptr<SpawnedTestServer> destination_server_;
+};
+
+TEST_F(URLRequestTestReferrerPolicy, HTTPToSameOriginHTTP) {
+  InstantiateSameOriginServers(SpawnedTestServer::TYPE_HTTP);
+
+  VerifyReferrerAfterRedirect(
+      URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
+      origin_server()->GetURL("path/to/file.html"),
+      origin_server()->GetURL("path/to/file.html"));
+
+  VerifyReferrerAfterRedirect(
+      URLRequest::REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN,
+      origin_server()->GetURL("path/to/file.html"),
+      origin_server()->GetURL("path/to/file.html"));
+
+  VerifyReferrerAfterRedirect(
+      URLRequest::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN,
+      origin_server()->GetURL("path/to/file.html"),
+      origin_server()->GetURL("path/to/file.html"));
+
+  VerifyReferrerAfterRedirect(URLRequest::NEVER_CLEAR_REFERRER,
+                              origin_server()->GetURL("path/to/file.html"),
+                              origin_server()->GetURL("path/to/file.html"));
+}
+
+TEST_F(URLRequestTestReferrerPolicy, HTTPToCrossOriginHTTP) {
+  InstantiateCrossOriginServers(SpawnedTestServer::TYPE_HTTP,
+                                SpawnedTestServer::TYPE_HTTP);
+
+  VerifyReferrerAfterRedirect(
+      URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
+      origin_server()->GetURL("path/to/file.html"),
+      origin_server()->GetURL("path/to/file.html"));
+
+  VerifyReferrerAfterRedirect(
+      URLRequest::REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN,
+      origin_server()->GetURL("path/to/file.html"),
+      origin_server()->GetURL(std::string()));
+
+  VerifyReferrerAfterRedirect(
+      URLRequest::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN,
+      origin_server()->GetURL("path/to/file.html"),
+      origin_server()->GetURL(std::string()));
+
+  VerifyReferrerAfterRedirect(URLRequest::NEVER_CLEAR_REFERRER,
+                              origin_server()->GetURL("path/to/file.html"),
+                              origin_server()->GetURL("path/to/file.html"));
+}
+
+TEST_F(URLRequestTestReferrerPolicy, HTTPSToSameOriginHTTPS) {
+  InstantiateSameOriginServers(SpawnedTestServer::TYPE_HTTPS);
+
+  VerifyReferrerAfterRedirect(
+      URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
+      origin_server()->GetURL("path/to/file.html"),
+      origin_server()->GetURL("path/to/file.html"));
+
+  VerifyReferrerAfterRedirect(
+      URLRequest::REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN,
+      origin_server()->GetURL("path/to/file.html"),
+      origin_server()->GetURL("path/to/file.html"));
+
+  VerifyReferrerAfterRedirect(
+      URLRequest::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN,
+      origin_server()->GetURL("path/to/file.html"),
+      origin_server()->GetURL("path/to/file.html"));
+
+  VerifyReferrerAfterRedirect(URLRequest::NEVER_CLEAR_REFERRER,
+                              origin_server()->GetURL("path/to/file.html"),
+                              origin_server()->GetURL("path/to/file.html"));
+}
+
+TEST_F(URLRequestTestReferrerPolicy, HTTPSToCrossOriginHTTPS) {
+  InstantiateCrossOriginServers(SpawnedTestServer::TYPE_HTTPS,
+                                SpawnedTestServer::TYPE_HTTPS);
+
+  VerifyReferrerAfterRedirect(
+      URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
+      origin_server()->GetURL("path/to/file.html"),
+      origin_server()->GetURL("path/to/file.html"));
+
+  VerifyReferrerAfterRedirect(
+      URLRequest::REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN,
+      origin_server()->GetURL("path/to/file.html"),
+      origin_server()->GetURL(std::string()));
+
+  VerifyReferrerAfterRedirect(
+      URLRequest::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN,
+      origin_server()->GetURL("path/to/file.html"),
+      origin_server()->GetURL(std::string()));
+
+  VerifyReferrerAfterRedirect(URLRequest::NEVER_CLEAR_REFERRER,
+                              origin_server()->GetURL("path/to/file.html"),
+                              origin_server()->GetURL("path/to/file.html"));
+}
+
+TEST_F(URLRequestTestReferrerPolicy, HTTPToHTTPS) {
+  InstantiateCrossOriginServers(SpawnedTestServer::TYPE_HTTP,
+                                SpawnedTestServer::TYPE_HTTPS);
+
+  VerifyReferrerAfterRedirect(
+      URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
+      origin_server()->GetURL("path/to/file.html"),
+      origin_server()->GetURL("path/to/file.html"));
+
+  VerifyReferrerAfterRedirect(
+      URLRequest::REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN,
+      origin_server()->GetURL("path/to/file.html"),
+      origin_server()->GetURL(std::string()));
+
+  VerifyReferrerAfterRedirect(
+      URLRequest::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN,
+      origin_server()->GetURL("path/to/file.html"),
+      origin_server()->GetURL(std::string()));
+
+  VerifyReferrerAfterRedirect(URLRequest::NEVER_CLEAR_REFERRER,
+                              origin_server()->GetURL("path/to/file.html"),
+                              origin_server()->GetURL("path/to/file.html"));
+}
+
+TEST_F(URLRequestTestReferrerPolicy, HTTPSToHTTP) {
+  InstantiateCrossOriginServers(SpawnedTestServer::TYPE_HTTPS,
+                                SpawnedTestServer::TYPE_HTTP);
+
+  VerifyReferrerAfterRedirect(
+      URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
+      origin_server()->GetURL("path/to/file.html"), GURL());
+
+  VerifyReferrerAfterRedirect(
+      URLRequest::REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN,
+      origin_server()->GetURL("path/to/file.html"), GURL());
+
+  VerifyReferrerAfterRedirect(
+      URLRequest::ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN,
+      origin_server()->GetURL("path/to/file.html"),
+      origin_server()->GetURL(std::string()));
+
+  VerifyReferrerAfterRedirect(URLRequest::NEVER_CLEAR_REFERRER,
+                              origin_server()->GetURL("path/to/file.html"),
+                              origin_server()->GetURL("path/to/file.html"));
+}
+
 class HTTPSRequestTest : public testing::Test {
  public:
   HTTPSRequestTest() : default_context_(true) {
@@ -7981,7 +8168,13 @@
   EXPECT_TRUE(cert_status & CERT_STATUS_REV_CHECKING_ENABLED);
 }
 
-TEST_F(HTTPSOCSPTest, RevokedStapled) {
+// Disabled on NSS ports. See https://crbug.com/431716.
+#if defined(USE_NSS)
+#define MAYBE_RevokedStapled DISABLED_RevokedStapled
+#else
+#define MAYBE_RevokedStapled RevokedStapled
+#endif
+TEST_F(HTTPSOCSPTest, MAYBE_RevokedStapled) {
   if (!SystemSupportsOCSPStapling()) {
     LOG(WARNING)
         << "Skipping test because system doesn't support OCSP stapling";
diff --git a/net/websockets/websocket_basic_handshake_stream.cc b/net/websockets/websocket_basic_handshake_stream.cc
index 769b802..08ee6ae 100644
--- a/net/websockets/websocket_basic_handshake_stream.cc
+++ b/net/websockets/websocket_basic_handshake_stream.cc
@@ -39,8 +39,8 @@
 #include "net/websockets/websocket_deflate_stream.h"
 #include "net/websockets/websocket_deflater.h"
 #include "net/websockets/websocket_extension_parser.h"
+#include "net/websockets/websocket_handshake_challenge.h"
 #include "net/websockets/websocket_handshake_constants.h"
-#include "net/websockets/websocket_handshake_handler.h"
 #include "net/websockets/websocket_handshake_request_info.h"
 #include "net/websockets/websocket_handshake_response_info.h"
 #include "net/websockets/websocket_stream.h"
@@ -435,8 +435,8 @@
                             requested_sub_protocols_,
                             &enriched_headers);
 
-  ComputeSecWebSocketAccept(handshake_challenge,
-                            &handshake_challenge_response_);
+  handshake_challenge_response_ =
+      ComputeSecWebSocketAccept(handshake_challenge);
 
   DCHECK(connect_delegate_);
   scoped_ptr<WebSocketHandshakeRequestInfo> request(
diff --git a/net/websockets/websocket_handshake_challenge.cc b/net/websockets/websocket_handshake_challenge.cc
new file mode 100644
index 0000000..3a1c3e8
--- /dev/null
+++ b/net/websockets/websocket_handshake_challenge.cc
@@ -0,0 +1,20 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/websockets/websocket_handshake_challenge.h"
+
+#include "base/base64.h"
+#include "base/sha1.h"
+#include "net/websockets/websocket_handshake_constants.h"
+
+namespace net {
+
+std::string ComputeSecWebSocketAccept(const std::string& key) {
+  std::string accept;
+  std::string hash = base::SHA1HashString(key + websockets::kWebSocketGuid);
+  base::Base64Encode(hash, &accept);
+  return accept;
+}
+
+}  // namespace net
diff --git a/net/websockets/websocket_handshake_challenge.h b/net/websockets/websocket_handshake_challenge.h
new file mode 100644
index 0000000..e21f2b0
--- /dev/null
+++ b/net/websockets/websocket_handshake_challenge.h
@@ -0,0 +1,21 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_CHALLENGE_H_
+#define NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_CHALLENGE_H_
+
+#include <string>
+
+#include "net/base/net_export.h"
+
+namespace net {
+
+// Given a WebSocket handshake challenge, compute the value that the server
+// should return in the Sec-WebSocket-Accept header.
+NET_EXPORT_PRIVATE std::string ComputeSecWebSocketAccept(
+    const std::string& key);
+
+}  // namespace net
+
+#endif  // NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_CHALLENGE_H_
diff --git a/net/websockets/websocket_handshake_challenge_test.cc b/net/websockets/websocket_handshake_challenge_test.cc
new file mode 100644
index 0000000..d7e45ca
--- /dev/null
+++ b/net/websockets/websocket_handshake_challenge_test.cc
@@ -0,0 +1,24 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/websockets/websocket_handshake_challenge.h"
+
+#include <string>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+namespace {
+
+// Test the example challenge from the RFC6455.
+TEST(WebSocketHandshakeChallengeTest, RFC6455) {
+  const std::string key = "dGhlIHNhbXBsZSBub25jZQ==";
+  std::string accept = ComputeSecWebSocketAccept(key);
+  EXPECT_EQ("s3pPLMBiTxaQ9kYGzzhZRbK+xOo=", accept);
+}
+
+}  // namespace
+
+}  // namespace net
diff --git a/net/websockets/websocket_handshake_handler.cc b/net/websockets/websocket_handshake_handler.cc
deleted file mode 100644
index 6bcc230..0000000
--- a/net/websockets/websocket_handshake_handler.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/websockets/websocket_handshake_handler.h"
-
-#include "base/base64.h"
-#include "base/logging.h"
-#include "base/sha1.h"
-#include "net/websockets/websocket_handshake_constants.h"
-
-namespace net {
-
-void ComputeSecWebSocketAccept(const std::string& key,
-                               std::string* accept) {
-  DCHECK(accept);
-
-  std::string hash =
-      base::SHA1HashString(key + websockets::kWebSocketGuid);
-  base::Base64Encode(hash, accept);
-}
-
-}  // namespace net
diff --git a/net/websockets/websocket_handshake_handler.h b/net/websockets/websocket_handshake_handler.h
deleted file mode 100644
index c65e6d9..0000000
--- a/net/websockets/websocket_handshake_handler.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_HANDLER_H_
-#define NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_HANDLER_H_
-
-#include <string>
-
-namespace net {
-
-// Given a WebSocket handshake challenge, compute the correct response.
-// TODO(ricea): There should probably be a test for this.
-void ComputeSecWebSocketAccept(const std::string& key,
-                               std::string* accept);
-
-}  // namespace net
-
-#endif  // NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_HANDLER_H_
diff --git a/net/websockets/websocket_handshake_handler_test.cc b/net/websockets/websocket_handshake_handler_test.cc
deleted file mode 100644
index 8eff571..0000000
--- a/net/websockets/websocket_handshake_handler_test.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/websockets/websocket_handshake_handler.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-
-namespace {
-
-// TODO(ricea): Put a test for ComputeSecWebSocketAccept() here.
-
-}  // namespace
-
-}  // namespace net