gfe-relnote: n/a(refactor only) Split out utility functions needed on quic
client side from SpdyUtils.

This is for avoiding dependency on GURL from libraries used by both server and client sides.

PiperOrigin-RevId: 256363427
Change-Id: I8aece427461710d3438e099c92d46394834a233c
diff --git a/quic/core/http/quic_client_promised_info.cc b/quic/core/http/quic_client_promised_info.cc
index 8b54969..6af35d5 100644
--- a/quic/core/http/quic_client_promised_info.cc
+++ b/quic/core/http/quic_client_promised_info.cc
@@ -7,7 +7,7 @@
 #include <string>
 #include <utility>
 
-#include "net/third_party/quiche/src/quic/core/http/spdy_utils.h"
+#include "net/third_party/quiche/src/quic/core/http/spdy_server_push_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
@@ -56,14 +56,14 @@
     Reset(QUIC_INVALID_PROMISE_METHOD);
     return false;
   }
-  if (!SpdyUtils::PromisedUrlIsValid(headers)) {
+  if (!SpdyServerPushUtils::PromisedUrlIsValid(headers)) {
     QUIC_DVLOG(1) << "Promise for stream " << id_ << " has invalid URL "
                   << url_;
     Reset(QUIC_INVALID_PROMISE_URL);
     return false;
   }
   if (!session_->IsAuthorized(
-          SpdyUtils::GetPromisedHostNameFromHeaders(headers))) {
+          SpdyServerPushUtils::GetPromisedHostNameFromHeaders(headers))) {
     Reset(QUIC_UNAUTHORIZED_PROMISE_URL);
     return false;
   }
diff --git a/quic/core/http/quic_client_promised_info_test.cc b/quic/core/http/quic_client_promised_info_test.cc
index fcc85ba..cd54dde 100644
--- a/quic/core/http/quic_client_promised_info_test.cc
+++ b/quic/core/http/quic_client_promised_info_test.cc
@@ -8,7 +8,7 @@
 #include <string>
 
 #include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.h"
-#include "net/third_party/quiche/src/quic/core/http/spdy_utils.h"
+#include "net/third_party/quiche/src/quic/core/http/spdy_server_push_utils.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
@@ -93,7 +93,8 @@
     push_promise_[":method"] = "GET";
     push_promise_[":scheme"] = "https";
 
-    promise_url_ = SpdyUtils::GetPromisedUrlFromHeaders(push_promise_);
+    promise_url_ =
+        SpdyServerPushUtils::GetPromisedUrlFromHeaders(push_promise_);
 
     client_request_ = push_promise_.Clone();
     promise_id_ = GetNthServerInitiatedUnidirectionalStreamId(
diff --git a/quic/core/http/quic_client_push_promise_index.cc b/quic/core/http/quic_client_push_promise_index.cc
index 0f11af4..877525a 100644
--- a/quic/core/http/quic_client_push_promise_index.cc
+++ b/quic/core/http/quic_client_push_promise_index.cc
@@ -7,7 +7,7 @@
 #include <string>
 
 #include "net/third_party/quiche/src/quic/core/http/quic_client_promised_info.h"
-#include "net/third_party/quiche/src/quic/core/http/spdy_utils.h"
+#include "net/third_party/quiche/src/quic/core/http/spdy_server_push_utils.h"
 
 using spdy::SpdyHeaderBlock;
 
@@ -32,7 +32,7 @@
     const spdy::SpdyHeaderBlock& request,
     QuicClientPushPromiseIndex::Delegate* delegate,
     TryHandle** handle) {
-  std::string url(SpdyUtils::GetPromisedUrlFromHeaders(request));
+  std::string url(SpdyServerPushUtils::GetPromisedUrlFromHeaders(request));
   auto it = promised_by_url_.find(url);
   if (it != promised_by_url_.end()) {
     QuicClientPromisedInfo* promised = it->second;
diff --git a/quic/core/http/quic_client_push_promise_index_test.cc b/quic/core/http/quic_client_push_promise_index_test.cc
index 401ea86..933ef6b 100644
--- a/quic/core/http/quic_client_push_promise_index_test.cc
+++ b/quic/core/http/quic_client_push_promise_index_test.cc
@@ -7,7 +7,7 @@
 #include <string>
 
 #include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_session.h"
-#include "net/third_party/quiche/src/quic/core/http/spdy_utils.h"
+#include "net/third_party/quiche/src/quic/core/http/spdy_server_push_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
 #include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
 #include "net/third_party/quiche/src/quic/test_tools/mock_quic_client_promised_info.h"
@@ -63,7 +63,7 @@
     request_[":version"] = "HTTP/1.1";
     request_[":method"] = "GET";
     request_[":scheme"] = "https";
-    url_ = SpdyUtils::GetPromisedUrlFromHeaders(request_);
+    url_ = SpdyServerPushUtils::GetPromisedUrlFromHeaders(request_);
   }
 
   MockQuicConnectionHelper helper_;
diff --git a/quic/core/http/quic_spdy_client_session_base.cc b/quic/core/http/quic_spdy_client_session_base.cc
index fe7e21c..9bb2ee2 100644
--- a/quic/core/http/quic_spdy_client_session_base.cc
+++ b/quic/core/http/quic_spdy_client_session_base.cc
@@ -7,7 +7,7 @@
 #include <string>
 
 #include "net/third_party/quiche/src/quic/core/http/quic_client_promised_info.h"
-#include "net/third_party/quiche/src/quic/core/http/spdy_utils.h"
+#include "net/third_party/quiche/src/quic/core/http/spdy_server_push_utils.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
@@ -119,7 +119,8 @@
     return false;
   }
 
-  const std::string url = SpdyUtils::GetPromisedUrlFromHeaders(headers);
+  const std::string url =
+      SpdyServerPushUtils::GetPromisedUrlFromHeaders(headers);
   QuicClientPromisedInfo* old_promised = GetPromisedByUrl(url);
   if (old_promised) {
     QUIC_DVLOG(1) << "Promise for stream " << promised_id
diff --git a/quic/core/http/quic_spdy_client_session_test.cc b/quic/core/http/quic_spdy_client_session_test.cc
index e6a6a91..716ae42 100644
--- a/quic/core/http/quic_spdy_client_session_test.cc
+++ b/quic/core/http/quic_spdy_client_session_test.cc
@@ -11,7 +11,7 @@
 #include "net/third_party/quiche/src/quic/core/crypto/null_decrypter.h"
 #include "net/third_party/quiche/src/quic/core/crypto/null_encrypter.h"
 #include "net/third_party/quiche/src/quic/core/http/quic_spdy_client_stream.h"
-#include "net/third_party/quiche/src/quic/core/http/spdy_utils.h"
+#include "net/third_party/quiche/src/quic/core/http/spdy_server_push_utils.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
@@ -107,7 +107,8 @@
     push_promise_[":version"] = "HTTP/1.1";
     push_promise_[":method"] = "GET";
     push_promise_[":scheme"] = "https";
-    promise_url_ = SpdyUtils::GetPromisedUrlFromHeaders(push_promise_);
+    promise_url_ =
+        SpdyServerPushUtils::GetPromisedUrlFromHeaders(push_promise_);
     promised_stream_id_ = GetNthServerInitiatedUnidirectionalStreamId(
         connection_->transport_version(), 0);
     associated_stream_id_ = GetNthClientInitiatedBidirectionalStreamId(
@@ -736,7 +737,7 @@
 
     // Verify that the promise is in the unclaimed streams map.
     std::string promise_url(
-        SpdyUtils::GetPromisedUrlFromHeaders(push_promise_));
+        SpdyServerPushUtils::GetPromisedUrlFromHeaders(push_promise_));
     EXPECT_NE(session_->GetPromisedByUrl(promise_url), nullptr);
     EXPECT_NE(session_->GetPromisedById(id), nullptr);
   }
@@ -754,7 +755,8 @@
       session_->HandlePromised(associated_stream_id_, id, push_promise_));
 
   // Verify that the promise was not created.
-  std::string promise_url(SpdyUtils::GetPromisedUrlFromHeaders(push_promise_));
+  std::string promise_url(
+      SpdyServerPushUtils::GetPromisedUrlFromHeaders(push_promise_));
   EXPECT_EQ(session_->GetPromisedById(id), nullptr);
   EXPECT_EQ(session_->GetPromisedByUrl(promise_url), nullptr);
 }
diff --git a/quic/core/http/spdy_server_push_utils.cc b/quic/core/http/spdy_server_push_utils.cc
new file mode 100644
index 0000000..02c963c
--- /dev/null
+++ b/quic/core/http/spdy_server_push_utils.cc
@@ -0,0 +1,214 @@
+// Copyright (c) 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/third_party/quiche/src/quic/core/http/spdy_server_push_utils.h"
+
+#include "url/gurl.h"
+
+using spdy::SpdyHeaderBlock;
+
+namespace quic {
+
+// static
+std::string SpdyServerPushUtils::GetPromisedUrlFromHeaders(
+    const SpdyHeaderBlock& headers) {
+  // RFC 7540, Section 8.1.2.3: All HTTP/2 requests MUST include exactly
+  // one valid value for the ":method", ":scheme", and ":path" pseudo-header
+  // fields, unless it is a CONNECT request.
+
+  // RFC 7540, Section  8.2.1:  The header fields in PUSH_PROMISE and any
+  // subsequent CONTINUATION frames MUST be a valid and complete set of request
+  // header fields (Section 8.1.2.3).  The server MUST include a method in the
+  // ":method" pseudo-header field that is safe and cacheable.
+  //
+  // RFC 7231, Section  4.2.1: Of the request methods defined by this
+  // specification, the GET, HEAD, OPTIONS, and TRACE methods are defined to be
+  // safe.
+  //
+  // RFC 7231, Section  4.2.1: ... this specification defines GET, HEAD, and
+  // POST as cacheable, ...
+  //
+  // So the only methods allowed in a PUSH_PROMISE are GET and HEAD.
+  SpdyHeaderBlock::const_iterator it = headers.find(":method");
+  if (it == headers.end() || (it->second != "GET" && it->second != "HEAD")) {
+    return std::string();
+  }
+
+  it = headers.find(":scheme");
+  if (it == headers.end() || it->second.empty()) {
+    return std::string();
+  }
+  QuicStringPiece scheme = it->second;
+
+  // RFC 7540, Section 8.2: The server MUST include a value in the
+  // ":authority" pseudo-header field for which the server is authoritative
+  // (see Section 10.1).
+  it = headers.find(":authority");
+  if (it == headers.end() || it->second.empty()) {
+    return std::string();
+  }
+  QuicStringPiece authority = it->second;
+
+  // RFC 7540, Section 8.1.2.3 requires that the ":path" pseudo-header MUST
+  // NOT be empty for "http" or "https" URIs;
+  //
+  // However, to ensure the scheme is consistently canonicalized, that check
+  // is deferred to implementations in QuicUrlUtils::GetPushPromiseUrl().
+  it = headers.find(":path");
+  if (it == headers.end()) {
+    return std::string();
+  }
+  QuicStringPiece path = it->second;
+
+  return GetPushPromiseUrl(scheme, authority, path);
+}
+
+// static
+std::string SpdyServerPushUtils::GetPromisedHostNameFromHeaders(
+    const SpdyHeaderBlock& headers) {
+  // TODO(fayang): Consider just checking out the value of the ":authority" key
+  // in headers.
+  return GURL(GetPromisedUrlFromHeaders(headers)).host();
+}
+
+// static
+bool SpdyServerPushUtils::PromisedUrlIsValid(const SpdyHeaderBlock& headers) {
+  std::string url(GetPromisedUrlFromHeaders(headers));
+  return !url.empty() && GURL(url).is_valid();
+}
+
+// static
+std::string SpdyServerPushUtils::GetPushPromiseUrl(QuicStringPiece scheme,
+                                                   QuicStringPiece authority,
+                                                   QuicStringPiece path) {
+  // RFC 7540, Section 8.1.2.3: The ":path" pseudo-header field includes the
+  // path and query parts of the target URI (the "path-absolute" production
+  // and optionally a '?' character followed by the "query" production (see
+  // Sections 3.3 and 3.4 of RFC3986). A request in asterisk form includes the
+  // value '*' for the ":path" pseudo-header field.
+  //
+  // This pseudo-header field MUST NOT be empty for "http" or "https" URIs;
+  // "http" or "https" URIs that do not contain a path MUST include a value of
+  // '/'. The exception to this rule is an OPTIONS request for an "http" or
+  // "https" URI that does not include a path component; these MUST include a
+  // ":path" pseudo-header with a value of '*' (see RFC7230, Section 5.3.4).
+  //
+  // In addition to the above restriction from RFC 7540, note that RFC3986
+  // defines the "path-absolute" construction as starting with "/" but not "//".
+  //
+  // RFC 7540, Section  8.2.1:  The header fields in PUSH_PROMISE and any
+  // subsequent CONTINUATION frames MUST be a valid and complete set of request
+  // header fields (Section 8.1.2.3).  The server MUST include a method in the
+  // ":method" pseudo-header field that is safe and cacheable.
+  //
+  // RFC 7231, Section  4.2.1:
+  // ... this specification defines GET, HEAD, and POST as cacheable, ...
+  //
+  // Since the OPTIONS method is not cacheable, it cannot be the method of a
+  // PUSH_PROMISE. Therefore, the exception mentioned in RFC 7540, Section
+  // 8.1.2.3 about OPTIONS requests does not apply here (i.e. ":path" cannot be
+  // "*").
+  if (path.empty() || path[0] != '/' || (path.size() >= 2 && path[1] == '/')) {
+    return std::string();
+  }
+
+  // Validate the scheme; this is to ensure a scheme of "foo://bar" is not
+  // parsed as a URL of "foo://bar://baz" when combined with a host of "baz".
+  std::string canonical_scheme;
+  url::StdStringCanonOutput canon_scheme_output(&canonical_scheme);
+  url::Component canon_component;
+  url::Component scheme_component(0, scheme.size());
+
+  if (!url::CanonicalizeScheme(scheme.data(), scheme_component,
+                               &canon_scheme_output, &canon_component) ||
+      !canon_component.is_nonempty() || canon_component.begin != 0) {
+    return std::string();
+  }
+  canonical_scheme.resize(canon_component.len + 1);
+
+  // Validate the authority; this is to ensure an authority such as
+  // "host/path" is not accepted, as when combined with a scheme like
+  // "http://", could result in a URL of "http://host/path".
+  url::Component auth_component(0, authority.size());
+  url::Component username_component;
+  url::Component password_component;
+  url::Component host_component;
+  url::Component port_component;
+
+  url::ParseAuthority(authority.data(), auth_component, &username_component,
+                      &password_component, &host_component, &port_component);
+
+  // RFC 7540, Section 8.1.2.3: The authority MUST NOT include the deprecated
+  // "userinfo" subcomponent for "http" or "https" schemed URIs.
+  //
+  // Note: Although |canonical_scheme| has not yet been checked for that, as
+  // it is performed later in processing, only "http" and "https" schemed
+  // URIs are supported for PUSH.
+  if (username_component.is_valid() || password_component.is_valid()) {
+    return std::string();
+  }
+
+  // Failed parsing or no host present. ParseAuthority() will ensure that
+  // host_component + port_component cover the entire string, if
+  // username_component and password_component are not present.
+  if (!host_component.is_nonempty()) {
+    return std::string();
+  }
+
+  // Validate the port (if present; it's optional).
+  int parsed_port_number = url::PORT_INVALID;
+  if (port_component.is_nonempty()) {
+    parsed_port_number = url::ParsePort(authority.data(), port_component);
+    if (parsed_port_number < 0 && parsed_port_number != url::PORT_UNSPECIFIED) {
+      return std::string();
+    }
+  }
+
+  // Validate the host by attempting to canonicalize it. Invalid characters
+  // will result in a canonicalization failure (e.g. '/')
+  std::string canon_host;
+  url::StdStringCanonOutput canon_host_output(&canon_host);
+  canon_component.reset();
+  if (!url::CanonicalizeHost(authority.data(), host_component,
+                             &canon_host_output, &canon_component) ||
+      !canon_component.is_nonempty() || canon_component.begin != 0) {
+    return std::string();
+  }
+
+  // At this point, "authority" has been validated to either be of the form
+  // 'host:port' or 'host', with 'host' being a valid domain or IP address,
+  // and 'port' (if present), being a valid port. Attempt to construct a
+  // URL of just the (scheme, host, port), which should be safe and will not
+  // result in ambiguous parsing.
+  //
+  // This also enforces that all PUSHed URLs are either HTTP or HTTPS-schemed
+  // URIs, consistent with the other restrictions enforced above.
+  //
+  // Note: url::CanonicalizeScheme() will have added the ':' to
+  // |canonical_scheme|.
+  GURL origin_url(canonical_scheme + "//" + std::string(authority));
+  if (!origin_url.is_valid() || !origin_url.SchemeIsHTTPOrHTTPS() ||
+      // The following checks are merely defense in depth.
+      origin_url.has_username() || origin_url.has_password() ||
+      (origin_url.has_path() && origin_url.path_piece() != "/") ||
+      origin_url.has_query() || origin_url.has_ref()) {
+    return std::string();
+  }
+
+  // Attempt to parse the path.
+  std::string spec = origin_url.GetWithEmptyPath().spec();
+  spec.pop_back();  // Remove the '/', as ":path" must contain it.
+  spec.append(std::string(path));
+
+  // Attempt to parse the full URL, with the path as well. Ensure there is no
+  // fragment to the query.
+  GURL full_url(spec);
+  if (!full_url.is_valid() || full_url.has_ref()) {
+    return std::string();
+  }
+
+  return full_url.spec();
+}
+
+}  // namespace quic
diff --git a/quic/core/http/spdy_server_push_utils.h b/quic/core/http/spdy_server_push_utils.h
new file mode 100644
index 0000000..3d11b65
--- /dev/null
+++ b/quic/core/http/spdy_server_push_utils.h
@@ -0,0 +1,43 @@
+// Copyright (c) 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.
+
+#ifndef QUICHE_QUIC_CORE_HTTP_SPDY_SERVER_PUSH_UTILS_H_
+#define QUICHE_QUIC_CORE_HTTP_SPDY_SERVER_PUSH_UTILS_H_
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h"
+
+namespace quic {
+
+class QUIC_EXPORT_PRIVATE SpdyServerPushUtils {
+ public:
+  SpdyServerPushUtils() = delete;
+
+  // Returns a canonicalized URL composed from the :scheme, :authority, and
+  // :path headers of a PUSH_PROMISE. Returns empty string if the headers do not
+  // conform to HTTP/2 spec or if the ":method" header contains a forbidden
+  // method for PUSH_PROMISE.
+  static std::string GetPromisedUrlFromHeaders(
+      const spdy::SpdyHeaderBlock& headers);
+
+  // Returns hostname, or empty string if missing.
+  static std::string GetPromisedHostNameFromHeaders(
+      const spdy::SpdyHeaderBlock& headers);
+
+  // Returns true if result of |GetPromisedUrlFromHeaders()| is non-empty
+  // and is a well-formed URL.
+  static bool PromisedUrlIsValid(const spdy::SpdyHeaderBlock& headers);
+
+  // Returns a canonical, valid URL for a PUSH_PROMISE with the specified
+  // ":scheme", ":authority", and ":path" header fields, or an empty
+  // string if the resulting URL is not valid or supported.
+  static std::string GetPushPromiseUrl(QuicStringPiece scheme,
+                                       QuicStringPiece authority,
+                                       QuicStringPiece path);
+};
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_HTTP_SPDY_SERVER_PUSH_UTILS_H_
diff --git a/quic/core/http/spdy_server_push_utils_test.cc b/quic/core/http/spdy_server_push_utils_test.cc
new file mode 100644
index 0000000..72d4a25
--- /dev/null
+++ b/quic/core/http/spdy_server_push_utils_test.cc
@@ -0,0 +1,221 @@
+// Copyright 2016 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/third_party/quiche/src/quic/core/http/spdy_server_push_utils.h"
+
+#include <memory>
+#include <string>
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
+
+using spdy::SpdyHeaderBlock;
+using testing::Pair;
+using testing::UnorderedElementsAre;
+
+namespace quic {
+namespace test {
+
+using GetPromisedUrlFromHeaders = QuicTest;
+
+TEST_F(GetPromisedUrlFromHeaders, Basic) {
+  SpdyHeaderBlock headers;
+  headers[":method"] = "GET";
+  EXPECT_EQ(SpdyServerPushUtils::GetPromisedUrlFromHeaders(headers), "");
+  headers[":scheme"] = "https";
+  EXPECT_EQ(SpdyServerPushUtils::GetPromisedUrlFromHeaders(headers), "");
+  headers[":authority"] = "www.google.com";
+  EXPECT_EQ(SpdyServerPushUtils::GetPromisedUrlFromHeaders(headers), "");
+  headers[":path"] = "/index.html";
+  EXPECT_EQ(SpdyServerPushUtils::GetPromisedUrlFromHeaders(headers),
+            "https://www.google.com/index.html");
+  headers["key1"] = "value1";
+  headers["key2"] = "value2";
+  EXPECT_EQ(SpdyServerPushUtils::GetPromisedUrlFromHeaders(headers),
+            "https://www.google.com/index.html");
+}
+
+TEST_F(GetPromisedUrlFromHeaders, Connect) {
+  SpdyHeaderBlock headers;
+  headers[":method"] = "CONNECT";
+  EXPECT_EQ(SpdyServerPushUtils::GetPromisedUrlFromHeaders(headers), "");
+  headers[":authority"] = "www.google.com";
+  EXPECT_EQ(SpdyServerPushUtils::GetPromisedUrlFromHeaders(headers), "");
+  headers[":scheme"] = "https";
+  EXPECT_EQ(SpdyServerPushUtils::GetPromisedUrlFromHeaders(headers), "");
+  headers[":path"] = "https";
+  EXPECT_EQ(SpdyServerPushUtils::GetPromisedUrlFromHeaders(headers), "");
+}
+
+TEST_F(GetPromisedUrlFromHeaders, InvalidUserinfo) {
+  SpdyHeaderBlock headers;
+  headers[":method"] = "GET";
+  headers[":authority"] = "user@www.google.com";
+  headers[":scheme"] = "https";
+  headers[":path"] = "/";
+  EXPECT_EQ(SpdyServerPushUtils::GetPromisedUrlFromHeaders(headers), "");
+}
+
+TEST_F(GetPromisedUrlFromHeaders, InvalidPath) {
+  SpdyHeaderBlock headers;
+  headers[":method"] = "GET";
+  headers[":authority"] = "www.google.com";
+  headers[":scheme"] = "https";
+  headers[":path"] = "";
+  EXPECT_EQ(SpdyServerPushUtils::GetPromisedUrlFromHeaders(headers), "");
+}
+
+using GetPromisedHostNameFromHeaders = QuicTest;
+
+TEST_F(GetPromisedHostNameFromHeaders, NormalUsage) {
+  SpdyHeaderBlock headers;
+  headers[":method"] = "GET";
+  EXPECT_EQ(SpdyServerPushUtils::GetPromisedHostNameFromHeaders(headers), "");
+  headers[":scheme"] = "https";
+  EXPECT_EQ(SpdyServerPushUtils::GetPromisedHostNameFromHeaders(headers), "");
+  headers[":authority"] = "www.google.com";
+  EXPECT_EQ(SpdyServerPushUtils::GetPromisedHostNameFromHeaders(headers), "");
+  headers[":path"] = "/index.html";
+  EXPECT_EQ(SpdyServerPushUtils::GetPromisedHostNameFromHeaders(headers),
+            "www.google.com");
+  headers["key1"] = "value1";
+  headers["key2"] = "value2";
+  EXPECT_EQ(SpdyServerPushUtils::GetPromisedHostNameFromHeaders(headers),
+            "www.google.com");
+  headers[":authority"] = "www.google.com:6666";
+  EXPECT_EQ(SpdyServerPushUtils::GetPromisedHostNameFromHeaders(headers),
+            "www.google.com");
+  headers[":authority"] = "192.168.1.1";
+  EXPECT_EQ(SpdyServerPushUtils::GetPromisedHostNameFromHeaders(headers),
+            "192.168.1.1");
+  headers[":authority"] = "192.168.1.1:6666";
+  EXPECT_EQ(SpdyServerPushUtils::GetPromisedHostNameFromHeaders(headers),
+            "192.168.1.1");
+}
+
+using PushPromiseUrlTest = QuicTest;
+
+TEST_F(PushPromiseUrlTest, GetPushPromiseUrl) {
+  // Test rejection of various inputs.
+  EXPECT_EQ("", SpdyServerPushUtils::GetPushPromiseUrl("file", "localhost",
+                                                       "/etc/password"));
+  EXPECT_EQ("", SpdyServerPushUtils::GetPushPromiseUrl(
+                    "file", "", "/C:/Windows/System32/Config/"));
+  EXPECT_EQ("", SpdyServerPushUtils::GetPushPromiseUrl(
+                    "", "https://www.google.com", "/"));
+
+  EXPECT_EQ("", SpdyServerPushUtils::GetPushPromiseUrl("https://www.google.com",
+                                                       "www.google.com", "/"));
+  EXPECT_EQ("", SpdyServerPushUtils::GetPushPromiseUrl("https://",
+                                                       "www.google.com", "/"));
+  EXPECT_EQ("", SpdyServerPushUtils::GetPushPromiseUrl("https", "", "/"));
+  EXPECT_EQ("", SpdyServerPushUtils::GetPushPromiseUrl("https", "",
+                                                       "www.google.com/"));
+  EXPECT_EQ("", SpdyServerPushUtils::GetPushPromiseUrl("https",
+                                                       "www.google.com/", "/"));
+  EXPECT_EQ("", SpdyServerPushUtils::GetPushPromiseUrl("https",
+                                                       "www.google.com", ""));
+  EXPECT_EQ("", SpdyServerPushUtils::GetPushPromiseUrl("https", "www.google",
+                                                       ".com/"));
+
+  // Test acception/rejection of various input combinations.
+  // |input_headers| is an array of pairs. The first value of each pair is a
+  // string that will be used as one of the inputs of GetPushPromiseUrl(). The
+  // second value of each pair is a bitfield where the lowest 3 bits indicate
+  // for which headers that string is valid (in a PUSH_PROMISE). For example,
+  // the string "http" would be valid for both the ":scheme" and ":authority"
+  // headers, so the bitfield paired with it is set to SCHEME | AUTH.
+  const unsigned char SCHEME = (1u << 0);
+  const unsigned char AUTH = (1u << 1);
+  const unsigned char PATH = (1u << 2);
+  const std::pair<const char*, unsigned char> input_headers[] = {
+      {"http", SCHEME | AUTH},
+      {"https", SCHEME | AUTH},
+      {"hTtP", SCHEME | AUTH},
+      {"HTTPS", SCHEME | AUTH},
+      {"www.google.com", AUTH},
+      {"90af90e0", AUTH},
+      {"12foo%20-bar:00001233", AUTH},
+      {"GOO\u200b\u2060\ufeffgoo", AUTH},
+      {"192.168.0.5", AUTH},
+      {"[::ffff:192.168.0.1.]", AUTH},
+      {"http:", AUTH},
+      {"bife l", AUTH},
+      {"/", PATH},
+      {"/foo/bar/baz", PATH},
+      {"/%20-2DVdkj.cie/foe_.iif/", PATH},
+      {"http://", 0},
+      {":443", 0},
+      {":80/eddd", 0},
+      {"google.com:-0", 0},
+      {"google.com:65536", 0},
+      {"http://google.com", 0},
+      {"http://google.com:39", 0},
+      {"//google.com/foo", 0},
+      {".com/", 0},
+      {"http://www.google.com/", 0},
+      {"http://foo:439", 0},
+      {"[::ffff:192.168", 0},
+      {"]/", 0},
+      {"//", 0}};
+  for (size_t i = 0; i < QUIC_ARRAYSIZE(input_headers); ++i) {
+    bool should_accept = (input_headers[i].second & SCHEME);
+    for (size_t j = 0; j < QUIC_ARRAYSIZE(input_headers); ++j) {
+      bool should_accept_2 = should_accept && (input_headers[j].second & AUTH);
+      for (size_t k = 0; k < QUIC_ARRAYSIZE(input_headers); ++k) {
+        // |should_accept_3| indicates whether or not GetPushPromiseUrl() is
+        // expected to accept this input combination.
+        bool should_accept_3 =
+            should_accept_2 && (input_headers[k].second & PATH);
+
+        std::string url = SpdyServerPushUtils::GetPushPromiseUrl(
+            input_headers[i].first, input_headers[j].first,
+            input_headers[k].first);
+
+        ::testing::AssertionResult result = ::testing::AssertionSuccess();
+        if (url.empty() == should_accept_3) {
+          result = ::testing::AssertionFailure()
+                   << "GetPushPromiseUrl() accepted/rejected the inputs when "
+                      "it shouldn't have."
+                   << std::endl
+                   << "     scheme: " << input_headers[i].first << std::endl
+                   << "  authority: " << input_headers[j].first << std::endl
+                   << "       path: " << input_headers[k].first << std::endl
+                   << "Output: " << url << std::endl;
+        }
+        ASSERT_TRUE(result);
+      }
+    }
+  }
+
+  // Test canonicalization of various valid inputs.
+  EXPECT_EQ("http://www.google.com/", SpdyServerPushUtils::GetPushPromiseUrl(
+                                          "http", "www.google.com", "/"));
+  EXPECT_EQ("https://www.goo-gle.com/fOOo/baRR",
+            SpdyServerPushUtils::GetPushPromiseUrl("hTtPs", "wWw.gOo-gLE.cOm",
+                                                   "/fOOo/baRR"));
+  EXPECT_EQ("https://www.goo-gle.com:3278/pAth/To/reSOurce",
+            SpdyServerPushUtils::GetPushPromiseUrl(
+                "hTtPs", "Www.gOo-Gle.Com:000003278", "/pAth/To/reSOurce"));
+  EXPECT_EQ("https://foo%20bar/foo/bar/baz",
+            SpdyServerPushUtils::GetPushPromiseUrl("https", "foo bar",
+                                                   "/foo/bar/baz"));
+  EXPECT_EQ("http://foo.com:70/e/", SpdyServerPushUtils::GetPushPromiseUrl(
+                                        "http", "foo.com:0000070", "/e/"));
+  EXPECT_EQ("http://192.168.0.1:70/e/",
+            SpdyServerPushUtils::GetPushPromiseUrl(
+                "http", "0300.0250.00.01:0070", "/e/"));
+  EXPECT_EQ("http://192.168.0.1/e/", SpdyServerPushUtils::GetPushPromiseUrl(
+                                         "http", "0xC0a80001", "/e/"));
+  EXPECT_EQ("http://[::c0a8:1]/", SpdyServerPushUtils::GetPushPromiseUrl(
+                                      "http", "[::192.168.0.1]", "/"));
+  EXPECT_EQ("https://[::ffff:c0a8:1]/",
+            SpdyServerPushUtils::GetPushPromiseUrl(
+                "https", "[::ffff:0xC0.0Xa8.0x0.0x1]", "/"));
+}
+
+}  // namespace test
+}  // namespace quic
diff --git a/quic/core/http/spdy_utils.cc b/quic/core/http/spdy_utils.cc
index 721ae33..d72a18d 100644
--- a/quic/core/http/spdy_utils.cc
+++ b/quic/core/http/spdy_utils.cc
@@ -8,15 +8,12 @@
 #include <string>
 #include <vector>
 
-#include "url/gurl.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_flag_utils.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_map_util.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_text_utils.h"
-#include "net/third_party/quiche/src/spdy/core/spdy_frame_builder.h"
-#include "net/third_party/quiche/src/spdy/core/spdy_framer.h"
 #include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
 
 using spdy::SpdyHeaderBlock;
@@ -131,74 +128,7 @@
 }
 
 // static
-std::string SpdyUtils::GetPromisedUrlFromHeaders(
-    const SpdyHeaderBlock& headers) {
-  // RFC 7540, Section 8.1.2.3: All HTTP/2 requests MUST include exactly
-  // one valid value for the ":method", ":scheme", and ":path" pseudo-header
-  // fields, unless it is a CONNECT request.
-
-  // RFC 7540, Section  8.2.1:  The header fields in PUSH_PROMISE and any
-  // subsequent CONTINUATION frames MUST be a valid and complete set of request
-  // header fields (Section 8.1.2.3).  The server MUST include a method in the
-  // ":method" pseudo-header field that is safe and cacheable.
-  //
-  // RFC 7231, Section  4.2.1: Of the request methods defined by this
-  // specification, the GET, HEAD, OPTIONS, and TRACE methods are defined to be
-  // safe.
-  //
-  // RFC 7231, Section  4.2.1: ... this specification defines GET, HEAD, and
-  // POST as cacheable, ...
-  //
-  // So the only methods allowed in a PUSH_PROMISE are GET and HEAD.
-  SpdyHeaderBlock::const_iterator it = headers.find(":method");
-  if (it == headers.end() || (it->second != "GET" && it->second != "HEAD")) {
-    return std::string();
-  }
-
-  it = headers.find(":scheme");
-  if (it == headers.end() || it->second.empty()) {
-    return std::string();
-  }
-  QuicStringPiece scheme = it->second;
-
-  // RFC 7540, Section 8.2: The server MUST include a value in the
-  // ":authority" pseudo-header field for which the server is authoritative
-  // (see Section 10.1).
-  it = headers.find(":authority");
-  if (it == headers.end() || it->second.empty()) {
-    return std::string();
-  }
-  QuicStringPiece authority = it->second;
-
-  // RFC 7540, Section 8.1.2.3 requires that the ":path" pseudo-header MUST
-  // NOT be empty for "http" or "https" URIs;
-  //
-  // However, to ensure the scheme is consistently canonicalized, that check
-  // is deferred to implementations in QuicUrlUtils::GetPushPromiseUrl().
-  it = headers.find(":path");
-  if (it == headers.end()) {
-    return std::string();
-  }
-  QuicStringPiece path = it->second;
-
-  return GetPushPromiseUrl(scheme, authority, path);
-}
-
-// static
-std::string SpdyUtils::GetPromisedHostNameFromHeaders(
-    const SpdyHeaderBlock& headers) {
-  // TODO(fayang): Consider just checking out the value of the ":authority" key
-  // in headers.
-  return GURL(GetPromisedUrlFromHeaders(headers)).host();
-}
-
-// static
-bool SpdyUtils::PromisedUrlIsValid(const SpdyHeaderBlock& headers) {
-  std::string url(GetPromisedUrlFromHeaders(headers));
-  return !url.empty() && GURL(url).is_valid();
-}
-
-// static
+// TODO(danzh): Move it to quic/tools/ and switch to use GURL.
 bool SpdyUtils::PopulateHeaderBlockFromUrl(const std::string url,
                                            SpdyHeaderBlock* headers) {
   (*headers)[":method"] = "GET";
@@ -219,137 +149,4 @@
   return true;
 }
 
-// static
-std::string SpdyUtils::GetPushPromiseUrl(QuicStringPiece scheme,
-                                         QuicStringPiece authority,
-                                         QuicStringPiece path) {
-  // RFC 7540, Section 8.1.2.3: The ":path" pseudo-header field includes the
-  // path and query parts of the target URI (the "path-absolute" production
-  // and optionally a '?' character followed by the "query" production (see
-  // Sections 3.3 and 3.4 of RFC3986). A request in asterisk form includes the
-  // value '*' for the ":path" pseudo-header field.
-  //
-  // This pseudo-header field MUST NOT be empty for "http" or "https" URIs;
-  // "http" or "https" URIs that do not contain a path MUST include a value of
-  // '/'. The exception to this rule is an OPTIONS request for an "http" or
-  // "https" URI that does not include a path component; these MUST include a
-  // ":path" pseudo-header with a value of '*' (see RFC7230, Section 5.3.4).
-  //
-  // In addition to the above restriction from RFC 7540, note that RFC3986
-  // defines the "path-absolute" construction as starting with "/" but not "//".
-  //
-  // RFC 7540, Section  8.2.1:  The header fields in PUSH_PROMISE and any
-  // subsequent CONTINUATION frames MUST be a valid and complete set of request
-  // header fields (Section 8.1.2.3).  The server MUST include a method in the
-  // ":method" pseudo-header field that is safe and cacheable.
-  //
-  // RFC 7231, Section  4.2.1:
-  // ... this specification defines GET, HEAD, and POST as cacheable, ...
-  //
-  // Since the OPTIONS method is not cacheable, it cannot be the method of a
-  // PUSH_PROMISE. Therefore, the exception mentioned in RFC 7540, Section
-  // 8.1.2.3 about OPTIONS requests does not apply here (i.e. ":path" cannot be
-  // "*").
-  if (path.empty() || path[0] != '/' || (path.size() >= 2 && path[1] == '/')) {
-    return std::string();
-  }
-
-  // Validate the scheme; this is to ensure a scheme of "foo://bar" is not
-  // parsed as a URL of "foo://bar://baz" when combined with a host of "baz".
-  std::string canonical_scheme;
-  url::StdStringCanonOutput canon_scheme_output(&canonical_scheme);
-  url::Component canon_component;
-  url::Component scheme_component(0, scheme.size());
-
-  if (!url::CanonicalizeScheme(scheme.data(), scheme_component,
-                               &canon_scheme_output, &canon_component) ||
-      !canon_component.is_nonempty() || canon_component.begin != 0) {
-    return std::string();
-  }
-  canonical_scheme.resize(canon_component.len + 1);
-
-  // Validate the authority; this is to ensure an authority such as
-  // "host/path" is not accepted, as when combined with a scheme like
-  // "http://", could result in a URL of "http://host/path".
-  url::Component auth_component(0, authority.size());
-  url::Component username_component;
-  url::Component password_component;
-  url::Component host_component;
-  url::Component port_component;
-
-  url::ParseAuthority(authority.data(), auth_component, &username_component,
-                      &password_component, &host_component, &port_component);
-
-  // RFC 7540, Section 8.1.2.3: The authority MUST NOT include the deprecated
-  // "userinfo" subcomponent for "http" or "https" schemed URIs.
-  //
-  // Note: Although |canonical_scheme| has not yet been checked for that, as
-  // it is performed later in processing, only "http" and "https" schemed
-  // URIs are supported for PUSH.
-  if (username_component.is_valid() || password_component.is_valid()) {
-    return std::string();
-  }
-
-  // Failed parsing or no host present. ParseAuthority() will ensure that
-  // host_component + port_component cover the entire string, if
-  // username_component and password_component are not present.
-  if (!host_component.is_nonempty()) {
-    return std::string();
-  }
-
-  // Validate the port (if present; it's optional).
-  int parsed_port_number = url::PORT_INVALID;
-  if (port_component.is_nonempty()) {
-    parsed_port_number = url::ParsePort(authority.data(), port_component);
-    if (parsed_port_number < 0 && parsed_port_number != url::PORT_UNSPECIFIED) {
-      return std::string();
-    }
-  }
-
-  // Validate the host by attempting to canonicalize it. Invalid characters
-  // will result in a canonicalization failure (e.g. '/')
-  std::string canon_host;
-  url::StdStringCanonOutput canon_host_output(&canon_host);
-  canon_component.reset();
-  if (!url::CanonicalizeHost(authority.data(), host_component,
-                             &canon_host_output, &canon_component) ||
-      !canon_component.is_nonempty() || canon_component.begin != 0) {
-    return std::string();
-  }
-
-  // At this point, "authority" has been validated to either be of the form
-  // 'host:port' or 'host', with 'host' being a valid domain or IP address,
-  // and 'port' (if present), being a valid port. Attempt to construct a
-  // URL of just the (scheme, host, port), which should be safe and will not
-  // result in ambiguous parsing.
-  //
-  // This also enforces that all PUSHed URLs are either HTTP or HTTPS-schemed
-  // URIs, consistent with the other restrictions enforced above.
-  //
-  // Note: url::CanonicalizeScheme() will have added the ':' to
-  // |canonical_scheme|.
-  GURL origin_url(canonical_scheme + "//" + std::string(authority));
-  if (!origin_url.is_valid() || !origin_url.SchemeIsHTTPOrHTTPS() ||
-      // The following checks are merely defense in depth.
-      origin_url.has_username() || origin_url.has_password() ||
-      (origin_url.has_path() && origin_url.path_piece() != "/") ||
-      origin_url.has_query() || origin_url.has_ref()) {
-    return std::string();
-  }
-
-  // Attempt to parse the path.
-  std::string spec = origin_url.GetWithEmptyPath().spec();
-  spec.pop_back();  // Remove the '/', as ":path" must contain it.
-  spec.append(std::string(path));
-
-  // Attempt to parse the full URL, with the path as well. Ensure there is no
-  // fragment to the query.
-  GURL full_url(spec);
-  if (!full_url.is_valid() || full_url.has_ref()) {
-    return std::string();
-  }
-
-  return full_url.spec();
-}
-
 }  // namespace quic
diff --git a/quic/core/http/spdy_utils.h b/quic/core/http/spdy_utils.h
index dc3fabc..4b962c2 100644
--- a/quic/core/http/spdy_utils.h
+++ b/quic/core/http/spdy_utils.h
@@ -12,7 +12,7 @@
 #include "net/third_party/quiche/src/quic/core/http/quic_header_list.h"
 #include "net/third_party/quiche/src/quic/core/quic_packets.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
-#include "net/third_party/quiche/src/spdy/core/spdy_framer.h"
+#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h"
 
 namespace quic {
 
@@ -46,32 +46,10 @@
                                       size_t* final_byte_offset,
                                       spdy::SpdyHeaderBlock* trailers);
 
-  // Returns a canonicalized URL composed from the :scheme, :authority, and
-  // :path headers of a PUSH_PROMISE. Returns empty string if the headers do not
-  // conform to HTTP/2 spec or if the ":method" header contains a forbidden
-  // method for PUSH_PROMISE.
-  static std::string GetPromisedUrlFromHeaders(
-      const spdy::SpdyHeaderBlock& headers);
-
-  // Returns hostname, or empty string if missing.
-  static std::string GetPromisedHostNameFromHeaders(
-      const spdy::SpdyHeaderBlock& headers);
-
-  // Returns true if result of |GetPromisedUrlFromHeaders()| is non-empty
-  // and is a well-formed URL.
-  static bool PromisedUrlIsValid(const spdy::SpdyHeaderBlock& headers);
-
   // Populates the fields of |headers| to make a GET request of |url|,
   // which must be fully-qualified.
   static bool PopulateHeaderBlockFromUrl(const std::string url,
                                          spdy::SpdyHeaderBlock* headers);
-
-  // Returns a canonical, valid URL for a PUSH_PROMISE with the specified
-  // ":scheme", ":authority", and ":path" header fields, or an empty
-  // string if the resulting URL is not valid or supported.
-  static std::string GetPushPromiseUrl(QuicStringPiece scheme,
-                                       QuicStringPiece authority,
-                                       QuicStringPiece path);
 };
 
 }  // namespace quic
diff --git a/quic/core/http/spdy_utils_test.cc b/quic/core/http/spdy_utils_test.cc
index d5c96fb..2ebf0cf 100644
--- a/quic/core/http/spdy_utils_test.cc
+++ b/quic/core/http/spdy_utils_test.cc
@@ -334,81 +334,6 @@
           Pair("key", "value")));
 }
 
-using GetPromisedUrlFromHeaders = QuicTest;
-
-TEST_F(GetPromisedUrlFromHeaders, Basic) {
-  SpdyHeaderBlock headers;
-  headers[":method"] = "GET";
-  EXPECT_EQ(SpdyUtils::GetPromisedUrlFromHeaders(headers), "");
-  headers[":scheme"] = "https";
-  EXPECT_EQ(SpdyUtils::GetPromisedUrlFromHeaders(headers), "");
-  headers[":authority"] = "www.google.com";
-  EXPECT_EQ(SpdyUtils::GetPromisedUrlFromHeaders(headers), "");
-  headers[":path"] = "/index.html";
-  EXPECT_EQ(SpdyUtils::GetPromisedUrlFromHeaders(headers),
-            "https://www.google.com/index.html");
-  headers["key1"] = "value1";
-  headers["key2"] = "value2";
-  EXPECT_EQ(SpdyUtils::GetPromisedUrlFromHeaders(headers),
-            "https://www.google.com/index.html");
-}
-
-TEST_F(GetPromisedUrlFromHeaders, Connect) {
-  SpdyHeaderBlock headers;
-  headers[":method"] = "CONNECT";
-  EXPECT_EQ(SpdyUtils::GetPromisedUrlFromHeaders(headers), "");
-  headers[":authority"] = "www.google.com";
-  EXPECT_EQ(SpdyUtils::GetPromisedUrlFromHeaders(headers), "");
-  headers[":scheme"] = "https";
-  EXPECT_EQ(SpdyUtils::GetPromisedUrlFromHeaders(headers), "");
-  headers[":path"] = "https";
-  EXPECT_EQ(SpdyUtils::GetPromisedUrlFromHeaders(headers), "");
-}
-
-TEST_F(GetPromisedUrlFromHeaders, InvalidUserinfo) {
-  SpdyHeaderBlock headers;
-  headers[":method"] = "GET";
-  headers[":authority"] = "user@www.google.com";
-  headers[":scheme"] = "https";
-  headers[":path"] = "/";
-  EXPECT_EQ(SpdyUtils::GetPromisedUrlFromHeaders(headers), "");
-}
-
-TEST_F(GetPromisedUrlFromHeaders, InvalidPath) {
-  SpdyHeaderBlock headers;
-  headers[":method"] = "GET";
-  headers[":authority"] = "www.google.com";
-  headers[":scheme"] = "https";
-  headers[":path"] = "";
-  EXPECT_EQ(SpdyUtils::GetPromisedUrlFromHeaders(headers), "");
-}
-
-using GetPromisedHostNameFromHeaders = QuicTest;
-
-TEST_F(GetPromisedHostNameFromHeaders, NormalUsage) {
-  SpdyHeaderBlock headers;
-  headers[":method"] = "GET";
-  EXPECT_EQ(SpdyUtils::GetPromisedHostNameFromHeaders(headers), "");
-  headers[":scheme"] = "https";
-  EXPECT_EQ(SpdyUtils::GetPromisedHostNameFromHeaders(headers), "");
-  headers[":authority"] = "www.google.com";
-  EXPECT_EQ(SpdyUtils::GetPromisedHostNameFromHeaders(headers), "");
-  headers[":path"] = "/index.html";
-  EXPECT_EQ(SpdyUtils::GetPromisedHostNameFromHeaders(headers),
-            "www.google.com");
-  headers["key1"] = "value1";
-  headers["key2"] = "value2";
-  EXPECT_EQ(SpdyUtils::GetPromisedHostNameFromHeaders(headers),
-            "www.google.com");
-  headers[":authority"] = "www.google.com:6666";
-  EXPECT_EQ(SpdyUtils::GetPromisedHostNameFromHeaders(headers),
-            "www.google.com");
-  headers[":authority"] = "192.168.1.1";
-  EXPECT_EQ(SpdyUtils::GetPromisedHostNameFromHeaders(headers), "192.168.1.1");
-  headers[":authority"] = "192.168.1.1:6666";
-  EXPECT_EQ(SpdyUtils::GetPromisedHostNameFromHeaders(headers), "192.168.1.1");
-}
-
 using PopulateHeaderBlockFromUrl = QuicTest;
 
 TEST_F(PopulateHeaderBlockFromUrl, NormalUsage) {
@@ -437,121 +362,5 @@
       SpdyUtils::PopulateHeaderBlockFromUrl("www.google.com/", &headers));
 }
 
-using PushPromiseUrlTest = QuicTest;
-
-TEST_F(PushPromiseUrlTest, GetPushPromiseUrl) {
-  // Test rejection of various inputs.
-  EXPECT_EQ("",
-            SpdyUtils::GetPushPromiseUrl("file", "localhost", "/etc/password"));
-  EXPECT_EQ("", SpdyUtils::GetPushPromiseUrl("file", "",
-                                             "/C:/Windows/System32/Config/"));
-  EXPECT_EQ("",
-            SpdyUtils::GetPushPromiseUrl("", "https://www.google.com", "/"));
-
-  EXPECT_EQ("", SpdyUtils::GetPushPromiseUrl("https://www.google.com",
-                                             "www.google.com", "/"));
-  EXPECT_EQ("",
-            SpdyUtils::GetPushPromiseUrl("https://", "www.google.com", "/"));
-  EXPECT_EQ("", SpdyUtils::GetPushPromiseUrl("https", "", "/"));
-  EXPECT_EQ("", SpdyUtils::GetPushPromiseUrl("https", "", "www.google.com/"));
-  EXPECT_EQ("", SpdyUtils::GetPushPromiseUrl("https", "www.google.com/", "/"));
-  EXPECT_EQ("", SpdyUtils::GetPushPromiseUrl("https", "www.google.com", ""));
-  EXPECT_EQ("", SpdyUtils::GetPushPromiseUrl("https", "www.google", ".com/"));
-
-  // Test acception/rejection of various input combinations.
-  // |input_headers| is an array of pairs. The first value of each pair is a
-  // string that will be used as one of the inputs of GetPushPromiseUrl(). The
-  // second value of each pair is a bitfield where the lowest 3 bits indicate
-  // for which headers that string is valid (in a PUSH_PROMISE). For example,
-  // the string "http" would be valid for both the ":scheme" and ":authority"
-  // headers, so the bitfield paired with it is set to SCHEME | AUTH.
-  const unsigned char SCHEME = (1u << 0);
-  const unsigned char AUTH = (1u << 1);
-  const unsigned char PATH = (1u << 2);
-  const std::pair<const char*, unsigned char> input_headers[] = {
-      {"http", SCHEME | AUTH},
-      {"https", SCHEME | AUTH},
-      {"hTtP", SCHEME | AUTH},
-      {"HTTPS", SCHEME | AUTH},
-      {"www.google.com", AUTH},
-      {"90af90e0", AUTH},
-      {"12foo%20-bar:00001233", AUTH},
-      {"GOO\u200b\u2060\ufeffgoo", AUTH},
-      {"192.168.0.5", AUTH},
-      {"[::ffff:192.168.0.1.]", AUTH},
-      {"http:", AUTH},
-      {"bife l", AUTH},
-      {"/", PATH},
-      {"/foo/bar/baz", PATH},
-      {"/%20-2DVdkj.cie/foe_.iif/", PATH},
-      {"http://", 0},
-      {":443", 0},
-      {":80/eddd", 0},
-      {"google.com:-0", 0},
-      {"google.com:65536", 0},
-      {"http://google.com", 0},
-      {"http://google.com:39", 0},
-      {"//google.com/foo", 0},
-      {".com/", 0},
-      {"http://www.google.com/", 0},
-      {"http://foo:439", 0},
-      {"[::ffff:192.168", 0},
-      {"]/", 0},
-      {"//", 0}};
-  for (size_t i = 0; i < QUIC_ARRAYSIZE(input_headers); ++i) {
-    bool should_accept = (input_headers[i].second & SCHEME);
-    for (size_t j = 0; j < QUIC_ARRAYSIZE(input_headers); ++j) {
-      bool should_accept_2 = should_accept && (input_headers[j].second & AUTH);
-      for (size_t k = 0; k < QUIC_ARRAYSIZE(input_headers); ++k) {
-        // |should_accept_3| indicates whether or not GetPushPromiseUrl() is
-        // expected to accept this input combination.
-        bool should_accept_3 =
-            should_accept_2 && (input_headers[k].second & PATH);
-
-        std::string url = SpdyUtils::GetPushPromiseUrl(input_headers[i].first,
-                                                       input_headers[j].first,
-                                                       input_headers[k].first);
-
-        ::testing::AssertionResult result = ::testing::AssertionSuccess();
-        if (url.empty() == should_accept_3) {
-          result = ::testing::AssertionFailure()
-                   << "GetPushPromiseUrl() accepted/rejected the inputs when "
-                      "it shouldn't have."
-                   << std::endl
-                   << "     scheme: " << input_headers[i].first << std::endl
-                   << "  authority: " << input_headers[j].first << std::endl
-                   << "       path: " << input_headers[k].first << std::endl
-                   << "Output: " << url << std::endl;
-        }
-        ASSERT_TRUE(result);
-      }
-    }
-  }
-
-  // Test canonicalization of various valid inputs.
-  EXPECT_EQ("http://www.google.com/",
-            SpdyUtils::GetPushPromiseUrl("http", "www.google.com", "/"));
-  EXPECT_EQ(
-      "https://www.goo-gle.com/fOOo/baRR",
-      SpdyUtils::GetPushPromiseUrl("hTtPs", "wWw.gOo-gLE.cOm", "/fOOo/baRR"));
-  EXPECT_EQ("https://www.goo-gle.com:3278/pAth/To/reSOurce",
-            SpdyUtils::GetPushPromiseUrl("hTtPs", "Www.gOo-Gle.Com:000003278",
-                                         "/pAth/To/reSOurce"));
-  EXPECT_EQ("https://foo%20bar/foo/bar/baz",
-            SpdyUtils::GetPushPromiseUrl("https", "foo bar", "/foo/bar/baz"));
-  EXPECT_EQ("http://foo.com:70/e/",
-            SpdyUtils::GetPushPromiseUrl("http", "foo.com:0000070", "/e/"));
-  EXPECT_EQ(
-      "http://192.168.0.1:70/e/",
-      SpdyUtils::GetPushPromiseUrl("http", "0300.0250.00.01:0070", "/e/"));
-  EXPECT_EQ("http://192.168.0.1/e/",
-            SpdyUtils::GetPushPromiseUrl("http", "0xC0a80001", "/e/"));
-  EXPECT_EQ("http://[::c0a8:1]/",
-            SpdyUtils::GetPushPromiseUrl("http", "[::192.168.0.1]", "/"));
-  EXPECT_EQ(
-      "https://[::ffff:c0a8:1]/",
-      SpdyUtils::GetPushPromiseUrl("https", "[::ffff:0xC0.0Xa8.0x0.0x1]", "/"));
-}
-
 }  // namespace test
 }  // namespace quic
diff --git a/quic/tools/quic_backend_response.h b/quic/tools/quic_backend_response.h
index 4ef0fdc..b578915 100644
--- a/quic/tools/quic_backend_response.h
+++ b/quic/tools/quic_backend_response.h
@@ -5,8 +5,8 @@
 #ifndef QUICHE_QUIC_TOOLS_QUIC_BACKEND_RESPONSE_H_
 #define QUICHE_QUIC_TOOLS_QUIC_BACKEND_RESPONSE_H_
 
-#include "net/third_party/quiche/src/quic/core/http/spdy_utils.h"
 #include "net/third_party/quiche/src/quic/tools/quic_url.h"
+#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
 
 namespace quic {
 
diff --git a/quic/tools/quic_simple_server_backend.h b/quic/tools/quic_simple_server_backend.h
index 74afb60..968ec66 100644
--- a/quic/tools/quic_simple_server_backend.h
+++ b/quic/tools/quic_simple_server_backend.h
@@ -5,6 +5,7 @@
 #ifndef QUICHE_QUIC_TOOLS_QUIC_SIMPLE_SERVER_BACKEND_H_
 #define QUICHE_QUIC_TOOLS_QUIC_SIMPLE_SERVER_BACKEND_H_
 
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
 #include "net/third_party/quiche/src/quic/tools/quic_backend_response.h"
 
 namespace spdy {