Commit 622b84ed authored by Tsuyoshi Horo's avatar Tsuyoshi Horo Committed by Commit Bot

Change the content-type for SignedHTTPExchange

After this cl, "application/signed-exchange;v=b0" will be used for SignedHTTPExchange.

Bug: 803774
Change-Id: I07e6218f07fb6917b1617ea208dcc7da31f13edf
Reviewed-on: https://chromium-review.googlesource.com/964024Reviewed-by: default avatarKunihiko Sakamoto <ksakamoto@chromium.org>
Reviewed-by: default avatarKouhei Ueno <kouhei@chromium.org>
Reviewed-by: default avatarKinuko Yasuda <kinuko@chromium.org>
Commit-Queue: Tsuyoshi Horo <horo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#543611}
parent afd36256
......@@ -343,9 +343,9 @@ IN_PROC_BROWSER_TEST_P(PrefetchBrowserTest, WebPackageWithPreload) {
RegisterResponse(
target_htxg,
// We mock the SignedExchangeHandler, so just return a HTML content
// as application/http-exchange+cbor.
// as "application/signed-exchange;v=b0".
ResponseEntry("<head><title>Prefetch Target (HTXG)</title></head>",
"application/http-exchange+cbor"));
"application/signed-exchange;v=b0"));
RegisterResponse(preload_url_in_htxg,
ResponseEntry("function foo() {}", "text/javascript"));
......
......@@ -64,6 +64,7 @@ void SignedExchangeHandler::SetVerificationTimeForTesting(
}
SignedExchangeHandler::SignedExchangeHandler(
std::string content_type,
std::unique_ptr<net::SourceStream> body,
ExchangeHeadersCallback headers_callback,
url::Origin request_initiator,
......@@ -81,12 +82,32 @@ SignedExchangeHandler::SignedExchangeHandler(
net::NetLogSourceType::CERT_VERIFIER_JOB)),
weak_factory_(this) {
DCHECK(base::FeatureList::IsEnabled(features::kSignedHTTPExchange));
TRACE_EVENT_BEGIN0(TRACE_DISABLED_BY_DEFAULT("loading"),
"SignedExchangeHandler::SignedExchangeHandler");
base::Optional<std::string> content_type_version_param;
if (!SignedExchangeHeaderParser::GetVersionParamFromContentType(
content_type, &content_type_version_param) ||
!content_type_version_param || *content_type_version_param != "b0") {
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&SignedExchangeHandler::RunErrorCallback,
weak_factory_.GetWeakPtr(), net::ERR_FAILED));
TRACE_EVENT_END2(TRACE_DISABLED_BY_DEFAULT("loading"),
"SignedExchangeHandler::SignedExchangeHandler", "error",
"Unsupported version of the content type. Currentry "
"content type must be "
"\"application/signed-exchange;v=b0\".",
"content-type", content_type);
return;
}
// Triggering the read (asynchronously) for the encoded header length.
SetupBuffers(SignedExchangeHeader::kEncodedHeaderLengthInBytes);
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&SignedExchangeHandler::DoHeaderLoop,
weak_factory_.GetWeakPtr()));
TRACE_EVENT_END0(TRACE_DISABLED_BY_DEFAULT("loading"),
"SignedExchangeCertFetcher::SignedExchangeHandler");
}
SignedExchangeHandler::~SignedExchangeHandler() = default;
......
......@@ -71,6 +71,7 @@ class CONTENT_EXPORT SignedExchangeHandler {
// and |url_loader_throttles_getter| are used to set up a network URLLoader to
// actually fetch the certificate.
SignedExchangeHandler(
std::string content_type,
std::unique_ptr<net::SourceStream> body,
ExchangeHeadersCallback headers_callback,
url::Origin request_initiator,
......
......@@ -188,6 +188,7 @@ class StructuredHeaderParser {
} // namespace
// static
base::Optional<std::vector<SignedExchangeHeaderParser::Signature>>
SignedExchangeHeaderParser::ParseSignature(base::StringPiece signature_str) {
TRACE_EVENT_BEGIN0(TRACE_DISABLED_BY_DEFAULT("loading"),
......@@ -279,6 +280,25 @@ SignedExchangeHeaderParser::ParseSignature(base::StringPiece signature_str) {
return signatures;
}
// static
bool SignedExchangeHeaderParser::GetVersionParamFromContentType(
base::StringPiece content_type,
base::Optional<std::string>* version_param) {
DCHECK(version_param);
StructuredHeaderParser parser(content_type);
ParameterisedLabel parameterised_label;
parser.ParseParameterisedLabel(&parameterised_label);
if (!parser.ParsedSuccessfully())
return false;
const auto it = parameterised_label.params.find("v");
if (it == parameterised_label.params.end()) {
*version_param = base::nullopt;
} else {
*version_param = it->second;
}
return true;
}
SignedExchangeHeaderParser::Signature::Signature() = default;
SignedExchangeHeaderParser::Signature::Signature(const Signature& other) =
default;
......
......@@ -43,6 +43,13 @@ class CONTENT_EXPORT SignedExchangeHeaderParser {
// https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html#rfc.section.3.2
static base::Optional<std::vector<Signature>> ParseSignature(
base::StringPiece signature_str);
// Parses |content_type| to get the value of "v=" parameter of the signed
// exchange. Example: "b0" for "application/signed-exchange;v=b0". Returns
// false if failed to parse.
static bool GetVersionParamFromContentType(
base::StringPiece content_type,
base::Optional<std::string>* version_param);
};
} // namespace content
......
......@@ -160,4 +160,53 @@ TEST_F(SignedExchangeHeaderParserTest, OpenQuoteAtEnd) {
EXPECT_FALSE(signatures.has_value());
}
TEST_F(SignedExchangeHeaderParserTest, VersionParam_None) {
const char content_type[] = "application/signed-exchange";
base::Optional<std::string> version;
EXPECT_TRUE(SignedExchangeHeaderParser::GetVersionParamFromContentType(
content_type, &version));
EXPECT_FALSE(version);
}
TEST_F(SignedExchangeHeaderParserTest, VersionParam_NoneWithSemicolon) {
const char content_type[] = "application/signed-exchange;";
base::Optional<std::string> version;
EXPECT_FALSE(SignedExchangeHeaderParser::GetVersionParamFromContentType(
content_type, &version));
}
TEST_F(SignedExchangeHeaderParserTest, VersionParam_EmptyString) {
const char content_type[] = "application/signed-exchange;v=";
base::Optional<std::string> version;
EXPECT_FALSE(SignedExchangeHeaderParser::GetVersionParamFromContentType(
content_type, &version));
}
TEST_F(SignedExchangeHeaderParserTest, VersionParam_Simple) {
const char content_type[] = "application/signed-exchange;v=b0";
base::Optional<std::string> version;
EXPECT_TRUE(SignedExchangeHeaderParser::GetVersionParamFromContentType(
content_type, &version));
ASSERT_TRUE(version);
EXPECT_EQ(*version, "b0");
}
TEST_F(SignedExchangeHeaderParserTest, VersionParam_SimpleWithSpace) {
const char content_type[] = "application/signed-exchange; v=b0";
base::Optional<std::string> version;
EXPECT_TRUE(SignedExchangeHeaderParser::GetVersionParamFromContentType(
content_type, &version));
ASSERT_TRUE(version);
EXPECT_EQ(*version, "b0");
}
TEST_F(SignedExchangeHeaderParserTest, VersionParam_SimpleWithDoublequotes) {
const char content_type[] = "application/signed-exchange;v=\"b0\"";
base::Optional<std::string> version;
EXPECT_TRUE(SignedExchangeHeaderParser::GetVersionParamFromContentType(
content_type, &version));
ASSERT_TRUE(version);
EXPECT_EQ(*version, "b0");
}
} // namespace content
......@@ -93,6 +93,12 @@ WebPackageLoader::WebPackageLoader(
request_context_getter_(std::move(request_context_getter)),
weak_factory_(this) {
DCHECK(base::FeatureList::IsEnabled(features::kSignedHTTPExchange));
// Can't use HttpResponseHeaders::GetMimeType() because SignedExchangeHandler
// checks "v=" parameter.
original_response.headers->EnumerateHeader(nullptr, "content-type",
&content_type_);
url_loader_.Bind(std::move(endpoints->url_loader));
if (url_loader_options_ &
......@@ -170,7 +176,7 @@ void WebPackageLoader::OnStartLoadingResponseBody(
}
signed_exchange_handler_ = std::make_unique<SignedExchangeHandler>(
std::make_unique<DataPipeToSourceStream>(std::move(body)),
content_type_, std::make_unique<DataPipeToSourceStream>(std::move(body)),
base::BindOnce(&WebPackageLoader::OnHTTPExchangeFound,
weak_factory_.GetWeakPtr()),
std::move(request_initiator_), std::move(url_loader_factory_),
......
......@@ -133,6 +133,8 @@ class WebPackageLoader final : public network::mojom::URLLoaderClient,
base::Optional<net::SSLInfo> ssl_info_;
std::string content_type_;
base::WeakPtrFactory<WebPackageLoader> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(WebPackageLoader);
......
......@@ -24,7 +24,7 @@ namespace content {
bool WebPackageRequestHandler::IsSupportedMimeType(
const std::string& mime_type) {
DCHECK(base::FeatureList::IsEnabled(features::kSignedHTTPExchange));
return mime_type == "application/http-exchange+cbor";
return mime_type == "application/signed-exchange";
}
WebPackageRequestHandler::WebPackageRequestHandler(
......
......@@ -218,6 +218,35 @@ IN_PROC_BROWSER_TEST_P(WebPackageRequestHandlerBrowserTest, Simple) {
EXPECT_EQ(original_fingerprint, fingerprint);
}
IN_PROC_BROWSER_TEST_P(WebPackageRequestHandlerBrowserTest,
InvalidContentType) {
InstallUrlInterceptor(
GURL("https://cert.example.org/cert.msg"),
"content/test/data/htxg/wildcard_example.org.public.pem.msg");
// Make the MockCertVerifier treat the certificate "wildcard.pem" as valid for
// "*.example.org".
scoped_refptr<net::X509Certificate> original_cert =
LoadCertificate("wildcard.pem");
net::CertVerifyResult dummy_result;
dummy_result.verified_cert = original_cert;
dummy_result.cert_status = net::OK;
mock_cert_verifier_->AddResultForCertAndHost(original_cert, "*.example.org",
dummy_result, net::OK);
embedded_test_server()->ServeFilesFromSourceDirectory("content/test/data");
ASSERT_TRUE(embedded_test_server()->Start());
GURL url = embedded_test_server()->GetURL(
"/htxg/test.example.org_test_invalid_content_type.htxg");
NavigationFailureObserver failure_observer(shell()->web_contents());
NavigateToURL(shell(), url);
EXPECT_TRUE(failure_observer.did_fail());
NavigationEntry* entry =
shell()->web_contents()->GetController().GetVisibleEntry();
EXPECT_EQ(content::PAGE_TYPE_ERROR, entry->GetPageType());
}
IN_PROC_BROWSER_TEST_P(WebPackageRequestHandlerBrowserTest, CertNotFound) {
InstallUrlInterceptor(GURL("https://cert.example.org/cert.msg"),
"content/test/data/htxg/404.msg");
......
HTTP/1.1 200 OK
Content-Type: application/http-exchange+cbor
Content-Type: application/signed-exchange;v=b0
HTTP/1.1 200 OK
Content-Type: application/http-exchange+cbor
Content-Type: application/signed-exchange;v=b0
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment