blob: c5950946e6cfc7478d1df647a787d69826eb2296 [file] [log] [blame]
// 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 "third_party/blink/renderer/platform/loader/cors/cors.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
namespace blink {
namespace {
class CorsExposedHeadersTest : public testing::Test {
public:
using CredentialsMode = network::mojom::FetchCredentialsMode;
WebHTTPHeaderSet Parse(CredentialsMode credentials_mode,
const AtomicString& header) const {
ResourceResponse response;
response.AddHttpHeaderField("access-control-expose-headers", header);
return cors::ExtractCorsExposedHeaderNamesList(credentials_mode, response);
}
};
TEST_F(CorsExposedHeadersTest, ValidInput) {
EXPECT_EQ(Parse(CredentialsMode::kOmit, "valid"),
WebHTTPHeaderSet({"valid"}));
EXPECT_EQ(Parse(CredentialsMode::kOmit, "a,b"), WebHTTPHeaderSet({"a", "b"}));
EXPECT_EQ(Parse(CredentialsMode::kOmit, " a , b "),
WebHTTPHeaderSet({"a", "b"}));
EXPECT_EQ(Parse(CredentialsMode::kOmit, " \t \t\t a"),
WebHTTPHeaderSet({"a"}));
EXPECT_EQ(Parse(CredentialsMode::kOmit, "a , "), WebHTTPHeaderSet({"a", ""}));
}
TEST_F(CorsExposedHeadersTest, DuplicatedEntries) {
EXPECT_EQ(Parse(CredentialsMode::kOmit, "a, a"), WebHTTPHeaderSet{"a"});
EXPECT_EQ(Parse(CredentialsMode::kOmit, "a, a, b"),
WebHTTPHeaderSet({"a", "b"}));
}
TEST_F(CorsExposedHeadersTest, InvalidInput) {
EXPECT_TRUE(Parse(CredentialsMode::kOmit, "not valid").empty());
EXPECT_TRUE(Parse(CredentialsMode::kOmit, "///").empty());
EXPECT_TRUE(Parse(CredentialsMode::kOmit, "/a/").empty());
EXPECT_TRUE(Parse(CredentialsMode::kOmit, ",").empty());
EXPECT_TRUE(Parse(CredentialsMode::kOmit, " , ").empty());
EXPECT_TRUE(Parse(CredentialsMode::kOmit, " , a").empty());
EXPECT_TRUE(Parse(CredentialsMode::kOmit, "").empty());
EXPECT_TRUE(Parse(CredentialsMode::kOmit, " ").empty());
// U+0141 which is 'A' (0x41) + 0x100.
EXPECT_TRUE(
Parse(CredentialsMode::kOmit, AtomicString(String::FromUTF8("\xC5\x81")))
.empty());
}
TEST_F(CorsExposedHeadersTest, Wildcard) {
ResourceResponse response;
response.AddHttpHeaderField("access-control-expose-headers", "a, b, *");
response.AddHttpHeaderField("b", "-");
response.AddHttpHeaderField("c", "-");
response.AddHttpHeaderField("d", "-");
response.AddHttpHeaderField("*", "-");
EXPECT_EQ(
cors::ExtractCorsExposedHeaderNamesList(CredentialsMode::kOmit, response),
WebHTTPHeaderSet({"access-control-expose-headers", "b", "c", "d", "*"}));
EXPECT_EQ(
cors::ExtractCorsExposedHeaderNamesList(CredentialsMode::kSameOrigin,
response),
WebHTTPHeaderSet({"access-control-expose-headers", "b", "c", "d", "*"}));
}
TEST_F(CorsExposedHeadersTest, Asterisk) {
ResourceResponse response;
response.AddHttpHeaderField("access-control-expose-headers", "a, b, *");
response.AddHttpHeaderField("b", "-");
response.AddHttpHeaderField("c", "-");
response.AddHttpHeaderField("d", "-");
response.AddHttpHeaderField("*", "-");
EXPECT_EQ(cors::ExtractCorsExposedHeaderNamesList(CredentialsMode::kInclude,
response),
WebHTTPHeaderSet({"a", "b", "*"}));
}
// Keep this in sync with the CalculateResponseTainting test in
// services/network/cors/cors_url_loader_unittest.cc.
TEST(CorsTest, CalculateResponseTainting) {
using network::mojom::FetchRequestMode;
using network::mojom::FetchResponseType;
const KURL same_origin_url("https://example.com/");
const KURL cross_origin_url("https://example2.com/");
scoped_refptr<SecurityOrigin> origin_refptr =
SecurityOrigin::Create(same_origin_url);
const SecurityOrigin* origin = origin_refptr.get();
const SecurityOrigin* no_origin = nullptr;
// CORS flag is false, same-origin request
EXPECT_EQ(FetchResponseType::kBasic,
cors::CalculateResponseTainting(same_origin_url,
FetchRequestMode::kSameOrigin,
origin, CorsFlag::Unset));
EXPECT_EQ(
FetchResponseType::kBasic,
cors::CalculateResponseTainting(
same_origin_url, FetchRequestMode::kNoCors, origin, CorsFlag::Unset));
EXPECT_EQ(
FetchResponseType::kBasic,
cors::CalculateResponseTainting(same_origin_url, FetchRequestMode::kCors,
origin, CorsFlag::Unset));
EXPECT_EQ(FetchResponseType::kBasic,
cors::CalculateResponseTainting(
same_origin_url, FetchRequestMode::kCorsWithForcedPreflight,
origin, CorsFlag::Unset));
EXPECT_EQ(FetchResponseType::kBasic,
cors::CalculateResponseTainting(same_origin_url,
FetchRequestMode::kNavigate, origin,
CorsFlag::Unset));
// CORS flag is false, cross-origin request
EXPECT_EQ(FetchResponseType::kOpaque,
cors::CalculateResponseTainting(cross_origin_url,
FetchRequestMode::kNoCors, origin,
CorsFlag::Unset));
EXPECT_EQ(FetchResponseType::kBasic,
cors::CalculateResponseTainting(cross_origin_url,
FetchRequestMode::kNavigate, origin,
CorsFlag::Unset));
// CORS flag is true, same-origin request
EXPECT_EQ(
FetchResponseType::kCors,
cors::CalculateResponseTainting(same_origin_url, FetchRequestMode::kCors,
origin, CorsFlag::Set));
EXPECT_EQ(FetchResponseType::kCors,
cors::CalculateResponseTainting(
same_origin_url, FetchRequestMode::kCorsWithForcedPreflight,
origin, CorsFlag::Set));
// CORS flag is true, cross-origin request
EXPECT_EQ(
FetchResponseType::kCors,
cors::CalculateResponseTainting(cross_origin_url, FetchRequestMode::kCors,
origin, CorsFlag::Set));
EXPECT_EQ(FetchResponseType::kCors,
cors::CalculateResponseTainting(
cross_origin_url, FetchRequestMode::kCorsWithForcedPreflight,
origin, CorsFlag::Set));
// Origin is not provided.
EXPECT_EQ(FetchResponseType::kBasic,
cors::CalculateResponseTainting(same_origin_url,
FetchRequestMode::kNoCors,
no_origin, CorsFlag::Unset));
EXPECT_EQ(FetchResponseType::kBasic,
cors::CalculateResponseTainting(same_origin_url,
FetchRequestMode::kNavigate,
no_origin, CorsFlag::Unset));
EXPECT_EQ(FetchResponseType::kBasic,
cors::CalculateResponseTainting(cross_origin_url,
FetchRequestMode::kNoCors,
no_origin, CorsFlag::Unset));
EXPECT_EQ(FetchResponseType::kBasic,
cors::CalculateResponseTainting(cross_origin_url,
FetchRequestMode::kNavigate,
no_origin, CorsFlag::Unset));
}
} // namespace
} // namespace blink