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 {