Reland "Fetch: Plumb request initiator through passthrough service workers."
This is a reland of da0a6501cf
This CL also includes a change to mark the two WPT tests as requiring
long timeout durations. On my fast build machine with an opt build
they take ~5 seconds each to complete and the default timeout is 10
seconds. On slower bots with debug builds its highly likely that these
tests would be marked as timing out. This change gives them a 60 second
timeout instead.
Original change's description:
> Fetch: Plumb request initiator through passthrough service workers.
>
> This CL contains essentially two changes:
>
> 1. The request initiator origin is plumbed through service workers
> that do `fetch(evt.request)`. In addition to plumbing, this
> requires changes to how we validate navigation requests in the
> CorsURLLoaderFactory.
> 2. Tracks the original destination of a request passed through a
> service worker. This is then used in the network service to force
> SameSite=Lax cookies to treat the request as a main frame navigation
> where appropriate.
>
> For more detailed information about these changes please see the
> internal design doc at:
>
> https://docs.google.com/document/d/1KZscujuV7bCFEnzJW-0DaCPU-I40RJimQKoCcI0umTQ/edit?usp=sharing
>
> In addition, there is some discussion of these features in the following
> spec issues:
>
> https://github.com/whatwg/fetch/issues/1321
> https://github.com/whatwg/fetch/issues/1327
>
> The test includes WPT tests that verify navigation headers and SameSite
> cookies. Note, chrome has a couple expected failures in the SameSite
> cookie tests because of the "lax-allowing-unsafe" intervention that is
> currently enabled. See:
>
> https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/web_tests/TestExpectations;l=4635;drc=e8133cbf2469adb99c6610483ab78bcfb8cc4c76
>
> Bug: 1115847,1241188
> Change-Id: I7e236fa20aeabb705aef40fcf8d5c36da6d2798c
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3115917
> Reviewed-by: Matt Menke <mmenke@chromium.org>
> Reviewed-by: Yutaka Hirano <yhirano@chromium.org>
> Reviewed-by: Nasko Oskov <nasko@chromium.org>
> Reviewed-by: Łukasz Anforowicz <lukasza@chromium.org>
> Commit-Queue: Ben Kelly <wanderview@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#936029}
Bug: 1115847,1241188
Change-Id: Ia26acbdd0d7ce6583d9a44f83ed086708657b8bd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3251368
Reviewed-by: Matt Menke <mmenke@chromium.org>
Reviewed-by: Yutaka Hirano <yhirano@chromium.org>
Reviewed-by: Nasko Oskov <nasko@chromium.org>
Reviewed-by: Łukasz Anforowicz <lukasza@chromium.org>
Auto-Submit: Ben Kelly <wanderview@chromium.org>
Commit-Queue: Ben Kelly <wanderview@chromium.org>
Cr-Commit-Position: refs/heads/main@{#936560}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
390d98b4f4
commit
2d91656608
content/common
net/url_request
services/network
BUILD.gn
cors
cors_url_loader.cccors_url_loader_factory.cccors_url_loader_factory_unittest.cccors_url_loader_unittest.cc
public
url_loader.ccthird_party/blink
public
mojom
renderer
core
modules
cache_storage
platform
loader
fetch
web_tests
external
wpt
service-workers
@ -54,10 +54,11 @@ blink::mojom::FetchAPIRequestPtr BackgroundFetchSettledFetch::CloneRequest(
|
||||
request->mode, request->is_main_resource_load, request->destination,
|
||||
request->frame_type, request->url, request->method, request->headers,
|
||||
CloneSerializedBlob(request->blob), request->body,
|
||||
request->referrer.Clone(), request->credentials_mode, request->cache_mode,
|
||||
request->redirect_mode, request->integrity, request->priority,
|
||||
request->fetch_window_id, request->keepalive, request->is_reload,
|
||||
request->is_history_navigation, request->devtools_stack_id);
|
||||
request->request_initiator, request->referrer.Clone(),
|
||||
request->credentials_mode, request->cache_mode, request->redirect_mode,
|
||||
request->integrity, request->priority, request->fetch_window_id,
|
||||
request->keepalive, request->is_reload, request->is_history_navigation,
|
||||
request->devtools_stack_id);
|
||||
}
|
||||
|
||||
} // namespace content
|
||||
|
@ -27,6 +27,7 @@ blink::mojom::FetchAPIRequestPtr TypeConverter<
|
||||
// nullptr.
|
||||
if (input.request_body)
|
||||
output->body = input.request_body;
|
||||
output->request_initiator = input.request_initiator;
|
||||
output->referrer = blink::mojom::Referrer::New(
|
||||
input.referrer,
|
||||
blink::ReferrerUtils::NetToMojoReferrerPolicy(input.referrer_policy));
|
||||
|
@ -563,6 +563,7 @@ URLRequest::URLRequest(const GURL& url,
|
||||
url_chain_(1, url),
|
||||
force_ignore_site_for_cookies_(false),
|
||||
force_ignore_top_frame_party_for_cookies_(false),
|
||||
force_main_frame_for_same_site_cookies_(false),
|
||||
method_("GET"),
|
||||
referrer_policy_(
|
||||
ReferrerPolicy::CLEAR_ON_TRANSITION_FROM_SECURE_TO_INSECURE),
|
||||
|
@ -293,6 +293,16 @@ class NET_EXPORT URLRequest : public base::SupportsUserData {
|
||||
force_ignore_top_frame_party_for_cookies_ = force;
|
||||
}
|
||||
|
||||
// Indicates if the request should be treated as a main frame navigation for
|
||||
// SameSite cookie computations. This flag overrides the IsolationInfo
|
||||
// request type associated with fetches from a service worker context.
|
||||
bool force_main_frame_for_same_site_cookies() const {
|
||||
return force_main_frame_for_same_site_cookies_;
|
||||
}
|
||||
void set_force_main_frame_for_same_site_cookies(bool value) {
|
||||
force_main_frame_for_same_site_cookies_ = value;
|
||||
}
|
||||
|
||||
// The first-party URL policy to apply when updating the first party URL
|
||||
// during redirects. The first-party URL policy may only be changed before
|
||||
// Start() is called.
|
||||
@ -913,6 +923,7 @@ class NET_EXPORT URLRequest : public base::SupportsUserData {
|
||||
|
||||
bool force_ignore_site_for_cookies_;
|
||||
bool force_ignore_top_frame_party_for_cookies_;
|
||||
bool force_main_frame_for_same_site_cookies_;
|
||||
absl::optional<url::Origin> initiator_;
|
||||
GURL delegate_redirect_url_;
|
||||
std::string method_; // "GET", "POST", etc. Should be all uppercase.
|
||||
|
@ -597,8 +597,10 @@ void URLRequestHttpJob::AddCookieHeaderAndStart() {
|
||||
request_->site_for_cookies())) {
|
||||
force_ignore_site_for_cookies = true;
|
||||
}
|
||||
bool is_main_frame_navigation = IsolationInfo::RequestType::kMainFrame ==
|
||||
request_->isolation_info().request_type();
|
||||
bool is_main_frame_navigation =
|
||||
IsolationInfo::RequestType::kMainFrame ==
|
||||
request_->isolation_info().request_type() ||
|
||||
request_->force_main_frame_for_same_site_cookies();
|
||||
CookieOptions::SameSiteCookieContext same_site_context =
|
||||
net::cookie_util::ComputeSameSiteContextForRequest(
|
||||
request_->method(), request_->url_chain(),
|
||||
|
@ -2518,6 +2518,31 @@ TEST_P(URLRequestSameSiteCookiesTest, SameSiteCookies) {
|
||||
EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
|
||||
}
|
||||
|
||||
// Verify that the lax cookie is sent for cross-site initiators when the
|
||||
// method is "safe" and the request is being forced to be considered as a
|
||||
// main frame navigation.
|
||||
{
|
||||
TestDelegate d;
|
||||
std::unique_ptr<URLRequest> req(default_context().CreateRequest(
|
||||
test_server.GetURL(kHost, "/echoheader?Cookie"), DEFAULT_PRIORITY, &d,
|
||||
TRAFFIC_ANNOTATION_FOR_TESTS));
|
||||
req->set_isolation_info(IsolationInfo::Create(
|
||||
IsolationInfo::RequestType::kOther, kOrigin, kOrigin, kSiteForCookies,
|
||||
{} /* party_context */));
|
||||
req->set_site_for_cookies(kSiteForCookies);
|
||||
req->set_initiator(kCrossOrigin);
|
||||
req->set_method("GET");
|
||||
req->set_force_main_frame_for_same_site_cookies(true);
|
||||
req->Start();
|
||||
d.RunUntilComplete();
|
||||
|
||||
EXPECT_EQ(std::string::npos,
|
||||
d.data_received().find("StrictSameSiteCookie=1"));
|
||||
EXPECT_NE(std::string::npos, d.data_received().find("LaxSameSiteCookie=1"));
|
||||
EXPECT_EQ(0, network_delegate.blocked_annotate_cookies_count());
|
||||
EXPECT_EQ(0, network_delegate.blocked_set_cookie_count());
|
||||
}
|
||||
|
||||
// Verify that neither cookie is sent for cross-site initiators when the
|
||||
// method is unsafe (e.g. POST), even if the request is a main frame
|
||||
// navigation.
|
||||
|
@ -427,6 +427,7 @@ source_set("tests") {
|
||||
"//jingle/glue:fake_ssl_socket",
|
||||
"//mojo/public/cpp/bindings",
|
||||
"//mojo/public/cpp/system",
|
||||
"//mojo/public/cpp/test_support:test_utils",
|
||||
"//net",
|
||||
"//net:extras",
|
||||
"//net:quic_test_tools",
|
||||
|
@ -294,6 +294,18 @@ void CorsURLLoader::FollowRedirect(
|
||||
const net::HttpRequestHeaders& modified_headers,
|
||||
const net::HttpRequestHeaders& modified_cors_exempt_headers,
|
||||
const absl::optional<GURL>& new_url) {
|
||||
// If this is a navigation from a renderer, then its a service worker
|
||||
// passthrough of a navigation request. Since this case uses manual
|
||||
// redirect mode FollowRedirect() should never be called.
|
||||
if (process_id_ != mojom::kBrowserProcessId &&
|
||||
request_.mode == mojom::RequestMode::kNavigate) {
|
||||
mojo::ReportBadMessage(
|
||||
"CorsURLLoader: navigate from non-browser-process should not call "
|
||||
"FollowRedirect");
|
||||
HandleComplete(URLLoaderCompletionStatus(net::ERR_FAILED));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!network_loader_ || !deferred_redirect_url_) {
|
||||
HandleComplete(URLLoaderCompletionStatus(net::ERR_FAILED));
|
||||
return;
|
||||
|
@ -383,18 +383,57 @@ bool CorsURLLoaderFactory::IsValidRequest(const ResourceRequest& request,
|
||||
return false;
|
||||
}
|
||||
|
||||
// The `force_main_frame_for_same_site_cookies` should only be set when a
|
||||
// service worker passes through a navigation request. In this case the
|
||||
// mode must be `kNavigate` and the destination must be empty.
|
||||
if (request.original_destination == mojom::RequestDestination::kDocument &&
|
||||
(request.mode != mojom::RequestMode::kNavigate ||
|
||||
request.destination != mojom::RequestDestination::kEmpty)) {
|
||||
mojo::ReportBadMessage(
|
||||
"CorsURLLoaderFactory: original_destination is unexpectedly set to "
|
||||
"kDocument");
|
||||
return false;
|
||||
}
|
||||
|
||||
// By default we compare the `request_initiator` to the lock below. This is
|
||||
// overridden for renderer navigations, however.
|
||||
absl::optional<url::Origin> origin_to_validate = request.request_initiator;
|
||||
|
||||
// Ensure that renderer requests are covered either by CORS or CORB.
|
||||
if (process_id_ != mojom::kBrowserProcessId) {
|
||||
switch (request.mode) {
|
||||
case mojom::RequestMode::kNavigate:
|
||||
// Only the browser process can initiate navigations. This helps ensure
|
||||
// that a malicious/compromised renderer cannot bypass CORB by issuing
|
||||
// kNavigate, rather than kNoCors requests. (CORB should apply only to
|
||||
// no-cors requests as tracked in https://crbug.com/953315 and as
|
||||
// captured in https://fetch.spec.whatwg.org/#main-fetch).
|
||||
mojo::ReportBadMessage(
|
||||
"CorsURLLoaderFactory: navigate from non-browser-process");
|
||||
return false;
|
||||
// A navigation request from a renderer can legally occur when a service
|
||||
// worker passes it through from its `FetchEvent.request` to `fetch()`.
|
||||
// In this case it is making a navigation request on behalf of the
|
||||
// original initiator. Since that initiator may be cross-origin, its
|
||||
// possible the request's initiator will not match our lock.
|
||||
//
|
||||
// To make this operation safe we instead compare the request URL origin
|
||||
// against the initiator lock. We can do this since service workers
|
||||
// should only ever handle same-origin navigations.
|
||||
//
|
||||
// With this approach its possible the initiator could be spoofed by the
|
||||
// renderer. However, since we have validated the request URL they can
|
||||
// only every lie to the origin that they have already compromised. It
|
||||
// does not allow an attacker to target other arbitrary origins.
|
||||
origin_to_validate = url::Origin::Create(request.url);
|
||||
|
||||
// We further validate the navigation request by ensuring it has the
|
||||
// correct redirect mode. This avoids an attacker attempting to
|
||||
// craft a navigation that is then automatically followed to a separate
|
||||
// target origin. With manual mode the redirect will instead be
|
||||
// processed as an opaque redirect response that is passed back to the
|
||||
// renderer and navigation code. The redirected requested must be
|
||||
// sent anew and go through this validation again.
|
||||
if (request.redirect_mode != mojom::RedirectMode::kManual) {
|
||||
mojo::ReportBadMessage(
|
||||
"CorsURLLoaderFactory: navigate from non-browser-process with "
|
||||
"redirect_mode set to 'follow'");
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case mojom::RequestMode::kSameOrigin:
|
||||
case mojom::RequestMode::kCors:
|
||||
@ -408,11 +447,11 @@ bool CorsURLLoaderFactory::IsValidRequest(const ResourceRequest& request,
|
||||
}
|
||||
}
|
||||
|
||||
// Compare |request_initiator| and |request_initiator_origin_lock_|.
|
||||
// Depending on the type of request, compare either `request_initiator` or
|
||||
// `request.url` to `request_initiator_origin_lock_`.
|
||||
InitiatorLockCompatibility initiator_lock_compatibility =
|
||||
VerifyRequestInitiatorLockWithPluginCheck(process_id_,
|
||||
request_initiator_origin_lock_,
|
||||
request.request_initiator);
|
||||
VerifyRequestInitiatorLockWithPluginCheck(
|
||||
process_id_, request_initiator_origin_lock_, origin_to_validate);
|
||||
UMA_HISTOGRAM_ENUMERATION(
|
||||
"NetworkService.URLLoader.RequestInitiatorOriginLockCompatibility",
|
||||
initiator_lock_compatibility);
|
||||
@ -440,7 +479,6 @@ bool CorsURLLoaderFactory::IsValidRequest(const ResourceRequest& request,
|
||||
|
||||
case InitiatorLockCompatibility::kIncorrectLock:
|
||||
// Requests from the renderer need to always specify a correct initiator.
|
||||
NOTREACHED();
|
||||
mojo::ReportBadMessage(
|
||||
"CorsURLLoaderFactory: lock VS initiator mismatch");
|
||||
return false;
|
||||
|
@ -7,6 +7,8 @@
|
||||
#include "base/macros.h"
|
||||
#include "base/test/task_environment.h"
|
||||
#include "mojo/public/cpp/bindings/remote.h"
|
||||
#include "mojo/public/cpp/test_support/fake_message_dispatch_context.h"
|
||||
#include "mojo/public/cpp/test_support/test_utils.h"
|
||||
#include "net/base/load_flags.h"
|
||||
#include "net/proxy_resolution/configured_proxy_resolution_service.h"
|
||||
#include "net/test/embedded_test_server/embedded_test_server.h"
|
||||
@ -111,6 +113,7 @@ class CorsURLLoaderFactoryTest : public testing::Test {
|
||||
private:
|
||||
// Test environment.
|
||||
base::test::TaskEnvironment task_environment_;
|
||||
mojo::FakeMessageDispatchContext mojo_context_;
|
||||
std::unique_ptr<net::URLRequestContext> url_request_context_;
|
||||
ResourceScheduler resource_scheduler_;
|
||||
std::unique_ptr<NetworkService> network_service_;
|
||||
@ -190,5 +193,77 @@ TEST_F(CorsURLLoaderFactoryTest, CleanupWithSharedCacheObjectInUse) {
|
||||
ResetFactory();
|
||||
}
|
||||
|
||||
TEST_F(CorsURLLoaderFactoryTest,
|
||||
NavigationFromRendererWithBadRequestURLOrigin) {
|
||||
ResourceRequest request;
|
||||
GURL url = test_server()->GetURL("/echoall");
|
||||
request.mode = mojom::RequestMode::kNavigate;
|
||||
request.redirect_mode = mojom::RedirectMode::kManual;
|
||||
request.destination = mojom::RequestDestination::kEmpty;
|
||||
request.method = net::HttpRequestHeaders::kPostMethod;
|
||||
request.url = GURL("https://some.other.origin/echoall");
|
||||
request.request_initiator = url::Origin::Create(url);
|
||||
mojo::test::BadMessageObserver bad_message_observer;
|
||||
CreateLoaderAndStart(request);
|
||||
EXPECT_EQ("CorsURLLoaderFactory: lock VS initiator mismatch",
|
||||
bad_message_observer.WaitForBadMessage());
|
||||
}
|
||||
|
||||
TEST_F(CorsURLLoaderFactoryTest, NavigationFromRendererWithBadRedirectMode) {
|
||||
ResourceRequest request;
|
||||
GURL url = test_server()->GetURL("/echoall");
|
||||
request.mode = mojom::RequestMode::kNavigate;
|
||||
request.redirect_mode = mojom::RedirectMode::kFollow;
|
||||
request.destination = mojom::RequestDestination::kEmpty;
|
||||
request.method = net::HttpRequestHeaders::kPostMethod;
|
||||
request.url = url;
|
||||
request.request_initiator = url::Origin::Create(url).DeriveNewOpaqueOrigin();
|
||||
mojo::test::BadMessageObserver bad_message_observer;
|
||||
CreateLoaderAndStart(request);
|
||||
EXPECT_EQ(
|
||||
"CorsURLLoaderFactory: navigate from non-browser-process with "
|
||||
"redirect_mode set to 'follow'",
|
||||
bad_message_observer.WaitForBadMessage());
|
||||
}
|
||||
|
||||
TEST_F(CorsURLLoaderFactoryTest, OriginalDestinationIsDocumentWithBadMode) {
|
||||
ResourceRequest request;
|
||||
GURL url = test_server()->GetURL("/echoall");
|
||||
request.mode = mojom::RequestMode::kCors;
|
||||
request.redirect_mode = mojom::RedirectMode::kFollow;
|
||||
request.destination = mojom::RequestDestination::kEmpty;
|
||||
request.method = net::HttpRequestHeaders::kGetMethod;
|
||||
request.url = url;
|
||||
request.request_initiator =
|
||||
url::Origin::Create(GURL("https://some.other.origin"));
|
||||
request.original_destination = mojom::RequestDestination::kDocument;
|
||||
mojo::test::BadMessageObserver bad_message_observer;
|
||||
CreateLoaderAndStart(request);
|
||||
EXPECT_EQ(
|
||||
"CorsURLLoaderFactory: original_destination is unexpectedly set to "
|
||||
"kDocument",
|
||||
bad_message_observer.WaitForBadMessage());
|
||||
}
|
||||
|
||||
TEST_F(CorsURLLoaderFactoryTest,
|
||||
OriginalDestinationIsDocumentWithBadDestination) {
|
||||
ResourceRequest request;
|
||||
GURL url = test_server()->GetURL("/echoall");
|
||||
request.mode = mojom::RequestMode::kNavigate;
|
||||
request.redirect_mode = mojom::RedirectMode::kManual;
|
||||
request.destination = mojom::RequestDestination::kIframe;
|
||||
request.method = net::HttpRequestHeaders::kGetMethod;
|
||||
request.url = url;
|
||||
request.request_initiator =
|
||||
url::Origin::Create(GURL("https://some.other.origin"));
|
||||
request.original_destination = mojom::RequestDestination::kDocument;
|
||||
mojo::test::BadMessageObserver bad_message_observer;
|
||||
CreateLoaderAndStart(request);
|
||||
EXPECT_EQ(
|
||||
"CorsURLLoaderFactory: original_destination is unexpectedly set to "
|
||||
"kDocument",
|
||||
bad_message_observer.WaitForBadMessage());
|
||||
}
|
||||
|
||||
} // namespace cors
|
||||
} // namespace network
|
||||
|
@ -207,12 +207,16 @@ class CorsURLLoaderTest : public testing::Test {
|
||||
}
|
||||
void SetUp() override { SetUp(mojom::NetworkContextParams::New()); }
|
||||
|
||||
void CreateLoaderAndStart(const GURL& origin,
|
||||
const GURL& url,
|
||||
mojom::RequestMode mode) {
|
||||
void CreateLoaderAndStart(
|
||||
const GURL& origin,
|
||||
const GURL& url,
|
||||
mojom::RequestMode mode,
|
||||
mojom::RedirectMode redirect_mode = mojom::RedirectMode::kFollow,
|
||||
mojom::CredentialsMode credentials_mode = mojom::CredentialsMode::kOmit) {
|
||||
ResourceRequest request;
|
||||
request.mode = mode;
|
||||
request.credentials_mode = mojom::CredentialsMode::kOmit;
|
||||
request.redirect_mode = redirect_mode;
|
||||
request.credentials_mode = credentials_mode;
|
||||
request.method = net::HttpRequestHeaders::kGetMethod;
|
||||
request.url = url;
|
||||
request.request_initiator = url::Origin::Create(origin);
|
||||
@ -702,9 +706,13 @@ TEST_F(CorsURLLoaderTest, NavigateWithEarlyHints) {
|
||||
}
|
||||
|
||||
TEST_F(CorsURLLoaderTest, NavigationFromRenderer) {
|
||||
ResetFactory(url::Origin::Create(GURL("https://example.com/")),
|
||||
kRendererProcessId);
|
||||
|
||||
ResourceRequest request;
|
||||
request.mode = mojom::RequestMode::kNavigate;
|
||||
request.url = GURL("https://example.com/");
|
||||
request.redirect_mode = mojom::RedirectMode::kManual;
|
||||
request.url = GURL("https://some.other.example.com/");
|
||||
request.request_initiator = absl::nullopt;
|
||||
|
||||
BadMessageTestHelper bad_message_helper;
|
||||
@ -718,7 +726,7 @@ TEST_F(CorsURLLoaderTest, NavigationFromRenderer) {
|
||||
EXPECT_EQ(net::ERR_INVALID_ARGUMENT, client().completion_status().error_code);
|
||||
EXPECT_THAT(bad_message_helper.bad_message_reports(),
|
||||
::testing::ElementsAre(
|
||||
"CorsURLLoaderFactory: navigate from non-browser-process"));
|
||||
"CorsURLLoaderFactory: lock VS initiator mismatch"));
|
||||
}
|
||||
|
||||
TEST_F(CorsURLLoaderTest, SameOriginRequest) {
|
||||
@ -2875,6 +2883,39 @@ TEST_F(CorsURLLoaderTest, PreflightMissingAllowOrigin) {
|
||||
mojom::CorsError::kPreflightMissingAllowOriginHeader)));
|
||||
}
|
||||
|
||||
TEST_F(CorsURLLoaderTest, NonBrowserNavigationRedirect) {
|
||||
BadMessageTestHelper bad_message_helper;
|
||||
|
||||
const GURL origin("https://example.com");
|
||||
const GURL url("https://example.com/foo.png");
|
||||
const GURL new_url("https://example.com/bar.png");
|
||||
|
||||
CreateLoaderAndStart(origin, url, mojom::RequestMode::kNavigate,
|
||||
mojom::RedirectMode::kManual,
|
||||
mojom::CredentialsMode::kInclude);
|
||||
RunUntilCreateLoaderAndStartCalled();
|
||||
|
||||
EXPECT_EQ(1, num_created_loaders());
|
||||
EXPECT_EQ(GetRequest().url, url);
|
||||
EXPECT_EQ(GetRequest().method, "GET");
|
||||
|
||||
NotifyLoaderClientOnReceiveRedirect(CreateRedirectInfo(301, "GET", new_url));
|
||||
RunUntilRedirectReceived();
|
||||
|
||||
EXPECT_TRUE(IsNetworkLoaderStarted());
|
||||
EXPECT_FALSE(client().has_received_completion());
|
||||
EXPECT_FALSE(client().has_received_response());
|
||||
EXPECT_TRUE(client().has_received_redirect());
|
||||
|
||||
FollowRedirect();
|
||||
|
||||
RunUntilComplete();
|
||||
EXPECT_THAT(
|
||||
bad_message_helper.bad_message_reports(),
|
||||
::testing::ElementsAre("CorsURLLoader: navigate from non-browser-process "
|
||||
"should not call FollowRedirect"));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace cors
|
||||
|
@ -144,6 +144,8 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ResourceRequest {
|
||||
mojom::RedirectMode redirect_mode = mojom::RedirectMode::kFollow;
|
||||
std::string fetch_integrity;
|
||||
mojom::RequestDestination destination = mojom::RequestDestination::kEmpty;
|
||||
mojom::RequestDestination original_destination =
|
||||
mojom::RequestDestination::kEmpty;
|
||||
scoped_refptr<ResourceRequestBody> request_body;
|
||||
bool keepalive = false;
|
||||
bool has_user_gesture = false;
|
||||
|
@ -218,6 +218,7 @@ bool StructTraits<
|
||||
out->is_fetch_like_api = data.is_fetch_like_api();
|
||||
out->is_favicon = data.is_favicon();
|
||||
out->obey_origin_policy = data.obey_origin_policy();
|
||||
out->original_destination = data.original_destination();
|
||||
out->target_ip_address_space = data.target_ip_address_space();
|
||||
return true;
|
||||
}
|
||||
|
@ -317,6 +317,10 @@ struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
|
||||
static bool obey_origin_policy(const network::ResourceRequest& request) {
|
||||
return request.obey_origin_policy;
|
||||
}
|
||||
static network::mojom::RequestDestination original_destination(
|
||||
const network::ResourceRequest& request) {
|
||||
return request.original_destination;
|
||||
}
|
||||
static const absl::optional<std::vector<net::SourceStream::SourceType>>&
|
||||
devtools_accepted_stream_types(const network::ResourceRequest& request) {
|
||||
return request.devtools_accepted_stream_types;
|
||||
|
@ -378,6 +378,10 @@ struct URLRequest {
|
||||
// Spec: https://wicg.github.io/origin-policy/
|
||||
bool obey_origin_policy;
|
||||
|
||||
// The original destination of a request that was passed through by a service
|
||||
// worker.
|
||||
RequestDestination original_destination;
|
||||
|
||||
// Params intended to be set by a trusted requestor which sends the request
|
||||
// to a trusted URLLoaderFactory. Note that the main implementation of
|
||||
// URLLoaderFactory is the one created in the network service via
|
||||
|
@ -610,6 +610,18 @@ URLLoader::URLLoader(
|
||||
if (ShouldForceIgnoreTopFramePartyForCookies())
|
||||
url_request_->set_force_ignore_top_frame_party_for_cookies(true);
|
||||
|
||||
// When a service worker forwards a navigation request it uses the
|
||||
// service worker's IsolationInfo. This causes the cookie code to fail
|
||||
// to send SameSite=Lax cookies for main-frame navigations passed through
|
||||
// a service worker. To fix this we check to see if the original destination
|
||||
// of the request was a main frame document and then set a flag indicating
|
||||
// SameSite cookies should treat it as a main frame navigation.
|
||||
if (request.mode == mojom::RequestMode::kNavigate &&
|
||||
request.destination == mojom::RequestDestination::kEmpty &&
|
||||
request.original_destination == mojom::RequestDestination::kDocument) {
|
||||
url_request_->set_force_main_frame_for_same_site_cookies(true);
|
||||
}
|
||||
|
||||
if (factory_params_->disable_secure_dns ||
|
||||
(request.trusted_params && request.trusted_params->disable_secure_dns)) {
|
||||
url_request_->SetSecureDnsPolicy(net::SecureDnsPolicy::kDisable);
|
||||
|
@ -14,6 +14,7 @@ import "services/network/public/mojom/url_request.mojom";
|
||||
import "third_party/blink/public/mojom/blob/serialized_blob.mojom";
|
||||
import "third_party/blink/public/mojom/loader/request_context_frame_type.mojom";
|
||||
import "third_party/blink/public/mojom/loader/referrer.mojom";
|
||||
import "url/mojom/origin.mojom";
|
||||
import "url/mojom/url.mojom";
|
||||
|
||||
|
||||
@ -162,6 +163,14 @@ struct FetchAPIRequest {
|
||||
SerializedBlob? blob;
|
||||
FetchAPIRequestBody? body;
|
||||
|
||||
// `request_initiator` indicates the origin that initiated the request. See
|
||||
// also `network::ResourceRequest::request_initiator`, and the doc comment
|
||||
// for `request_initiator` in services/network/public/mojom/url_request.mojom.
|
||||
//
|
||||
// Note that the origin may be missing for browser-initiated navigations
|
||||
// (e.g. ones initiated from the Omnibox).
|
||||
url.mojom.Origin? request_initiator;
|
||||
|
||||
Referrer? referrer;
|
||||
network.mojom.CredentialsMode credentials_mode =
|
||||
network.mojom.CredentialsMode.kOmit;
|
||||
|
@ -762,22 +762,7 @@ void FetchManager::Loader::PerformHTTPFetch() {
|
||||
request.SetHttpMethod(fetch_request_data_->Method());
|
||||
request.SetFetchWindowId(fetch_request_data_->WindowId());
|
||||
request.SetTrustTokenParams(fetch_request_data_->TrustTokenParams());
|
||||
|
||||
switch (fetch_request_data_->Mode()) {
|
||||
case RequestMode::kSameOrigin:
|
||||
case RequestMode::kNoCors:
|
||||
case RequestMode::kCors:
|
||||
case RequestMode::kCorsWithForcedPreflight:
|
||||
request.SetMode(fetch_request_data_->Mode());
|
||||
break;
|
||||
case RequestMode::kNavigate:
|
||||
// NetworkService (i.e. CorsURLLoaderFactory::IsSane) rejects kNavigate
|
||||
// requests coming from renderers, so using kSameOrigin here.
|
||||
// TODO(lukasza): Tweak CorsURLLoaderFactory::IsSane to accept kNavigate
|
||||
// if request_initiator and the target are same-origin.
|
||||
request.SetMode(RequestMode::kSameOrigin);
|
||||
break;
|
||||
}
|
||||
request.SetMode(fetch_request_data_->Mode());
|
||||
|
||||
request.SetCredentialsMode(fetch_request_data_->Credentials());
|
||||
for (const auto& header : fetch_request_data_->HeaderList()->List()) {
|
||||
@ -825,6 +810,8 @@ void FetchManager::Loader::PerformHTTPFetch() {
|
||||
UseCounter::Count(execution_context_, mojom::WebFeature::kFetchKeepalive);
|
||||
}
|
||||
|
||||
request.SetOriginalDestination(fetch_request_data_->OriginalDestination());
|
||||
|
||||
// "3. Append `Host`, ..."
|
||||
// FIXME: Implement this when the spec is fixed.
|
||||
|
||||
|
@ -164,6 +164,8 @@ FetchRequestData* FetchRequestData::Create(
|
||||
// we deprecate SetContext.
|
||||
|
||||
request->SetDestination(fetch_api_request->destination);
|
||||
if (fetch_api_request->request_initiator)
|
||||
request->SetOrigin(fetch_api_request->request_initiator);
|
||||
request->SetReferrerString(AtomicString(Referrer::NoReferrer()));
|
||||
if (fetch_api_request->referrer) {
|
||||
if (!fetch_api_request->referrer->url.IsEmpty()) {
|
||||
@ -184,6 +186,7 @@ FetchRequestData* FetchRequestData::Create(
|
||||
fetch_api_request->priority));
|
||||
if (fetch_api_request->fetch_window_id)
|
||||
request->SetWindowId(fetch_api_request->fetch_window_id.value());
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
@ -205,6 +208,7 @@ FetchRequestData* FetchRequestData::CloneExceptBody() {
|
||||
request->integrity_ = integrity_;
|
||||
request->priority_ = priority_;
|
||||
request->importance_ = importance_;
|
||||
request->original_destination_ = original_destination_;
|
||||
request->keepalive_ = keepalive_;
|
||||
request->is_history_navigation_ = is_history_navigation_;
|
||||
request->window_id_ = window_id_;
|
||||
|
@ -108,6 +108,15 @@ class CORE_EXPORT FetchRequestData final
|
||||
void SetIntegrity(const String& integrity) { integrity_ = integrity; }
|
||||
ResourceLoadPriority Priority() const { return priority_; }
|
||||
void SetPriority(ResourceLoadPriority priority) { priority_ = priority; }
|
||||
|
||||
// The original destination of a request passed through by a service worker.
|
||||
void SetOriginalDestination(network::mojom::RequestDestination value) {
|
||||
original_destination_ = value;
|
||||
}
|
||||
network::mojom::RequestDestination OriginalDestination() const {
|
||||
return original_destination_;
|
||||
}
|
||||
|
||||
bool Keepalive() const { return keepalive_; }
|
||||
void SetKeepalive(bool b) { keepalive_ = b; }
|
||||
bool IsHistoryNavigation() const { return is_history_navigation_; }
|
||||
@ -174,6 +183,8 @@ class CORE_EXPORT FetchRequestData final
|
||||
String mime_type_;
|
||||
String integrity_;
|
||||
ResourceLoadPriority priority_;
|
||||
network::mojom::RequestDestination original_destination_ =
|
||||
network::mojom::RequestDestination::kEmpty;
|
||||
bool keepalive_;
|
||||
bool is_history_navigation_ = false;
|
||||
// A specific factory that should be used for this request instead of whatever
|
||||
|
19
third_party/blink/renderer/core/fetch/request.cc
vendored
19
third_party/blink/renderer/core/fetch/request.cc
vendored
@ -70,7 +70,8 @@ FetchRequestData* CreateCopyOfFetchRequestDataForFetch(
|
||||
request->SetURL(original->Url());
|
||||
request->SetMethod(original->Method());
|
||||
request->SetHeaderList(original->HeaderList()->Clone());
|
||||
request->SetOrigin(context->GetSecurityOrigin());
|
||||
request->SetOrigin(original->Origin() ? original->Origin()
|
||||
: context->GetSecurityOrigin());
|
||||
// FIXME: Set client.
|
||||
DOMWrapperWorld& world = script_state->World();
|
||||
if (world.IsIsolatedWorld()) {
|
||||
@ -97,6 +98,18 @@ FetchRequestData* CreateCopyOfFetchRequestDataForFetch(
|
||||
}
|
||||
request->SetWindowId(original->WindowId());
|
||||
request->SetTrustTokenParams(original->TrustTokenParams());
|
||||
|
||||
// When a new request is created from another the destination is always reset
|
||||
// to be `kEmpty`. In order to facilitate some later checks when a service
|
||||
// worker forwards a navigation request we want to keep track of the
|
||||
// destination of the original request. Therefore record the original
|
||||
// request's destination if its non-empty, otherwise just carry forward
|
||||
// whatever "original destination" value was already set.
|
||||
if (original->Destination() != network::mojom::RequestDestination::kEmpty)
|
||||
request->SetOriginalDestination(original->Destination());
|
||||
else
|
||||
request->SetOriginalDestination(original->OriginalDestination());
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
@ -319,6 +332,9 @@ Request* Request::CreateRequestWithRequestOrString(
|
||||
|
||||
// "If any of |init|'s members are present, then:"
|
||||
if (AreAnyMembersPresent(init)) {
|
||||
request->SetOrigin(execution_context->GetSecurityOrigin());
|
||||
request->SetOriginalDestination(network::mojom::RequestDestination::kEmpty);
|
||||
|
||||
// "If |request|'s |mode| is "navigate", then set it to "same-origin".
|
||||
if (request->Mode() == network::mojom::RequestMode::kNavigate)
|
||||
request->SetMode(network::mojom::RequestMode::kSameOrigin);
|
||||
@ -982,6 +998,7 @@ mojom::blink::FetchAPIRequestPtr Request::CreateFetchAPIRequest() const {
|
||||
fetch_api_request->integrity = request_->Integrity();
|
||||
fetch_api_request->is_history_navigation = request_->IsHistoryNavigation();
|
||||
fetch_api_request->destination = request_->Destination();
|
||||
fetch_api_request->request_initiator = request_->Origin();
|
||||
|
||||
// Strip off the fragment part of URL. So far, all callers expect the fragment
|
||||
// to be excluded.
|
||||
|
@ -268,11 +268,12 @@ class ResponsesAccumulator : public RefCounted<ResponsesAccumulator> {
|
||||
auto request_clone_without_body = mojom::blink::FetchAPIRequest::New(
|
||||
request->mode, request->is_main_resource_load, request->destination,
|
||||
request->frame_type, request->url, request->method, request->headers,
|
||||
nullptr /* blob */, ResourceRequestBody(), request->referrer.Clone(),
|
||||
request->credentials_mode, request->cache_mode,
|
||||
request->redirect_mode, request->integrity, request->priority,
|
||||
request->fetch_window_id, request->keepalive, request->is_reload,
|
||||
request->is_history_navigation, request->devtools_stack_id);
|
||||
nullptr /* blob */, ResourceRequestBody(), request->request_initiator,
|
||||
request->referrer.Clone(), request->credentials_mode,
|
||||
request->cache_mode, request->redirect_mode, request->integrity,
|
||||
request->priority, request->fetch_window_id, request->keepalive,
|
||||
request->is_reload, request->is_history_navigation,
|
||||
request->devtools_stack_id);
|
||||
cache_remote_->Match(
|
||||
std::move(request), mojom::blink::CacheQueryOptions::New(),
|
||||
/*in_related_fetch_event=*/false, /*in_range_fetch_event=*/false,
|
||||
|
@ -513,6 +513,14 @@ class PLATFORM_EXPORT ResourceRequestHead {
|
||||
return allowHTTP1ForStreamingUpload_;
|
||||
}
|
||||
|
||||
// The original destination of a request passed through by a service worker.
|
||||
network::mojom::RequestDestination GetOriginalDestination() const {
|
||||
return original_destination_;
|
||||
}
|
||||
void SetOriginalDestination(network::mojom::RequestDestination value) {
|
||||
original_destination_ = value;
|
||||
}
|
||||
|
||||
const absl::optional<ResourceRequestHead::WebBundleTokenParams>&
|
||||
GetWebBundleTokenParams() const {
|
||||
return web_bundle_token_params_;
|
||||
@ -603,6 +611,9 @@ class PLATFORM_EXPORT ResourceRequestHead {
|
||||
|
||||
base::UnguessableToken fetch_window_id_;
|
||||
|
||||
network::mojom::RequestDestination original_destination_ =
|
||||
network::mojom::RequestDestination::kEmpty;
|
||||
|
||||
uint64_t inspector_id_ = 0;
|
||||
|
||||
bool is_from_origin_dirty_style_sheet_ = false;
|
||||
|
@ -421,6 +421,8 @@ void PopulateResourceRequest(const ResourceRequestHead& src,
|
||||
dest->headers.SetHeaderIfMissing(net::HttpRequestHeaders::kAccept,
|
||||
network::kDefaultAcceptHeaderValue);
|
||||
}
|
||||
|
||||
dest->original_destination = src.GetOriginalDestination();
|
||||
}
|
||||
|
||||
} // namespace blink
|
||||
|
559
third_party/blink/web_tests/external/wpt/service-workers/service-worker/navigation-headers.https.html
vendored
Normal file
559
third_party/blink/web_tests/external/wpt/service-workers/service-worker/navigation-headers.https.html
vendored
Normal file
@ -0,0 +1,559 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="timeout" content="long">
|
||||
<title>Service Worker: Navigation Post Request Origin Header</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/common/get-host-info.sub.js"></script>
|
||||
<script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script>
|
||||
<body>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
const script = new URL('./resources/fetch-rewrite-worker.js', self.location);
|
||||
const base = './resources/navigation-headers-server.py';
|
||||
const scope = base + '?with-sw';
|
||||
let registration;
|
||||
|
||||
async function post_and_get_headers(t, form_host, method, swaction) {
|
||||
if (swaction === 'navpreload') {
|
||||
assert_true('navigationPreload' in registration,
|
||||
'navigation preload must be supported');
|
||||
}
|
||||
let target_string;
|
||||
if (swaction === 'no-sw') {
|
||||
target_string = base + '?no-sw';
|
||||
} else if (swaction === 'fallback') {
|
||||
target_string = `${scope}&ignore`;
|
||||
} else {
|
||||
target_string = `${scope}&${swaction}`;
|
||||
}
|
||||
const target = new URL(target_string, self.location);
|
||||
|
||||
let popup_url_path;
|
||||
if (method === 'GET') {
|
||||
popup_url_path = './resources/location-setter.html';
|
||||
} else if (method === 'POST') {
|
||||
popup_url_path = './resources/form-poster.html';
|
||||
}
|
||||
|
||||
const popup_url = new URL(popup_url_path, self.location);
|
||||
const tmp_params = new URLSearchParams();
|
||||
tmp_params.set('target', encodeURIComponent(target));
|
||||
popup_url.hostname = form_host;
|
||||
popup_url.search = tmp_params.toString();
|
||||
|
||||
const message_promise = new Promise(resolve => {
|
||||
self.addEventListener('message', evt => {
|
||||
resolve(evt.data);
|
||||
});
|
||||
});
|
||||
|
||||
const frame = await with_iframe(popup_url);
|
||||
t.add_cleanup(() => frame.remove());
|
||||
|
||||
return await message_promise;
|
||||
}
|
||||
|
||||
const SAME_ORIGIN = new URL(self.location.origin);
|
||||
const SAME_SITE = new URL(get_host_info().HTTPS_REMOTE_ORIGIN);
|
||||
const CROSS_SITE = new URL(get_host_info().HTTPS_NOTSAMESITE_ORIGIN);
|
||||
|
||||
promise_test(async t => {
|
||||
registration = await service_worker_unregister_and_register(t, script, scope);
|
||||
await wait_for_state(t, registration.installing, 'activated');
|
||||
if (registration.navigationPreload)
|
||||
await registration.navigationPreload.enable();
|
||||
}, 'Setup service worker');
|
||||
|
||||
//
|
||||
// Origin and referer headers
|
||||
//
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_ORIGIN.hostname, 'GET',
|
||||
'no-sw');
|
||||
assert_equals(result.origin, 'not set', 'origin header');
|
||||
assert_equals(result.referer, SAME_ORIGIN.href, 'referer header');
|
||||
}, 'GET Navigation, same-origin with no service worker sets correct ' +
|
||||
'origin and referer headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_ORIGIN.hostname, 'POST',
|
||||
'no-sw');
|
||||
assert_equals(result.origin, SAME_ORIGIN.origin, 'origin header');
|
||||
assert_equals(result.referer, SAME_ORIGIN.href, 'referer header');
|
||||
}, 'POST Navigation, same-origin with no service worker sets correct ' +
|
||||
'origin and referer headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_ORIGIN.hostname, 'GET',
|
||||
'passthrough');
|
||||
assert_equals(result.origin, 'not set', 'origin header');
|
||||
assert_equals(result.referer, SAME_ORIGIN.href, 'referer header');
|
||||
}, 'GET Navigation, same-origin with passthrough service worker sets correct ' +
|
||||
'origin and referer headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_ORIGIN.hostname, 'POST',
|
||||
'passthrough');
|
||||
assert_equals(result.origin, SAME_ORIGIN.origin, 'origin header');
|
||||
assert_equals(result.referer, SAME_ORIGIN.href, 'referer header');
|
||||
}, 'POST Navigation, same-origin with passthrough service worker sets correct ' +
|
||||
'origin and referer headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_ORIGIN.hostname, 'GET',
|
||||
'fallback');
|
||||
assert_equals(result.origin, 'not set', 'origin header');
|
||||
assert_equals(result.referer, SAME_ORIGIN.href, 'referer header');
|
||||
}, 'GET Navigation, same-origin with fallback service worker sets correct ' +
|
||||
'origin and referer headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_ORIGIN.hostname, 'POST',
|
||||
'fallback');
|
||||
assert_equals(result.origin, SAME_ORIGIN.origin, 'origin header');
|
||||
assert_equals(result.referer, SAME_ORIGIN.href, 'referer header');
|
||||
}, 'POST Navigation, same-origin with fallback service worker sets correct ' +
|
||||
'origin and referer headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_ORIGIN.hostname, 'GET',
|
||||
'navpreload');
|
||||
assert_equals(result.origin, 'not set', 'origin header');
|
||||
assert_equals(result.referer, SAME_ORIGIN.href, 'referer header');
|
||||
}, 'GET Navigation, same-origin with navpreload service worker sets correct ' +
|
||||
'origin and referer headers.');
|
||||
|
||||
// There is no POST test for navpreload since the feature only supports GET
|
||||
// requests.
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_ORIGIN.hostname, 'GET',
|
||||
'change-request');
|
||||
assert_equals(result.origin, 'not set', 'origin header');
|
||||
assert_equals(result.referer, script.href, 'referer header');
|
||||
}, 'GET Navigation, same-origin with service worker that changes the ' +
|
||||
'request sets correct origin and referer headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_ORIGIN.hostname, 'POST',
|
||||
'change-request');
|
||||
assert_equals(result.origin, SAME_ORIGIN.origin, 'origin header');
|
||||
assert_equals(result.referer, script.href, 'referer header');
|
||||
}, 'POST Navigation, same-origin with service worker that changes the ' +
|
||||
'request sets correct origin and referer headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_SITE.hostname, 'GET',
|
||||
'no-sw');
|
||||
assert_equals(result.origin, 'not set', 'origin header');
|
||||
assert_equals(result.referer, SAME_SITE.href, 'referer header');
|
||||
}, 'GET Navigation, same-site with no service worker sets correct ' +
|
||||
'origin and referer headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_SITE.hostname, 'POST',
|
||||
'no-sw');
|
||||
assert_equals(result.origin, SAME_SITE.origin, 'origin header');
|
||||
assert_equals(result.referer, SAME_SITE.href, 'referer header');
|
||||
}, 'POST Navigation, same-site with no service worker sets correct ' +
|
||||
'origin and referer headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_SITE.hostname, 'GET',
|
||||
'passthrough');
|
||||
assert_equals(result.origin, 'not set', 'origin header');
|
||||
assert_equals(result.referer, SAME_SITE.href, 'referer header');
|
||||
}, 'GET Navigation, same-site with passthrough service worker sets correct ' +
|
||||
'origin and referer headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_SITE.hostname, 'POST',
|
||||
'passthrough');
|
||||
assert_equals(result.origin, SAME_SITE.origin, 'origin header');
|
||||
assert_equals(result.referer, SAME_SITE.href, 'referer header');
|
||||
}, 'POST Navigation, same-site with passthrough service worker sets correct ' +
|
||||
'origin and referer headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_SITE.hostname, 'GET',
|
||||
'fallback');
|
||||
assert_equals(result.origin, 'not set', 'origin header');
|
||||
assert_equals(result.referer, SAME_SITE.href, 'referer header');
|
||||
}, 'GET Navigation, same-site with fallback service worker sets correct ' +
|
||||
'origin and referer headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_SITE.hostname, 'POST',
|
||||
'fallback');
|
||||
assert_equals(result.origin, SAME_SITE.origin, 'origin header');
|
||||
assert_equals(result.referer, SAME_SITE.href, 'referer header');
|
||||
}, 'POST Navigation, same-site with fallback service worker sets correct ' +
|
||||
'origin and referer headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_SITE.hostname, 'GET',
|
||||
'navpreload');
|
||||
assert_equals(result.origin, 'not set', 'origin header');
|
||||
assert_equals(result.referer, SAME_SITE.href, 'referer header');
|
||||
}, 'GET Navigation, same-site with navpreload service worker sets correct ' +
|
||||
'origin and referer headers.');
|
||||
|
||||
// There is no POST test for navpreload since the feature only supports GET
|
||||
// requests.
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_SITE.hostname, 'GET',
|
||||
'change-request');
|
||||
assert_equals(result.origin, 'not set', 'origin header');
|
||||
assert_equals(result.referer, script.href, 'referer header');
|
||||
}, 'GET Navigation, same-site with service worker that changes the ' +
|
||||
'request sets correct origin and referer headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_SITE.hostname, 'POST',
|
||||
'change-request');
|
||||
assert_equals(result.origin, SAME_ORIGIN.origin, 'origin header');
|
||||
assert_equals(result.referer, script.href, 'referer header');
|
||||
}, 'POST Navigation, same-site with service worker that changes the ' +
|
||||
'request sets correct origin and referer headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, CROSS_SITE.hostname, 'GET',
|
||||
'no-sw');
|
||||
assert_equals(result.origin, 'not set', 'origin header');
|
||||
assert_equals(result.referer, CROSS_SITE.href, 'referer header');
|
||||
}, 'GET Navigation, cross-site with no service worker sets correct ' +
|
||||
'origin and referer headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, CROSS_SITE.hostname, 'POST',
|
||||
'no-sw');
|
||||
assert_equals(result.origin, CROSS_SITE.origin, 'origin header');
|
||||
assert_equals(result.referer, CROSS_SITE.href, 'referer header');
|
||||
}, 'POST Navigation, cross-site with no service worker sets correct ' +
|
||||
'origin and referer headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, CROSS_SITE.hostname, 'GET',
|
||||
'passthrough');
|
||||
assert_equals(result.origin, 'not set', 'origin header');
|
||||
assert_equals(result.referer, CROSS_SITE.href, 'referer header');
|
||||
}, 'GET Navigation, cross-site with passthrough service worker sets correct ' +
|
||||
'origin and referer headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, CROSS_SITE.hostname, 'POST',
|
||||
'passthrough');
|
||||
assert_equals(result.origin, CROSS_SITE.origin, 'origin header');
|
||||
assert_equals(result.referer, CROSS_SITE.href, 'referer header');
|
||||
}, 'POST Navigation, cross-site with passthrough service worker sets correct ' +
|
||||
'origin and referer headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, CROSS_SITE.hostname, 'GET',
|
||||
'fallback');
|
||||
assert_equals(result.origin, 'not set', 'origin header');
|
||||
assert_equals(result.referer, CROSS_SITE.href, 'referer header');
|
||||
}, 'GET Navigation, cross-site with fallback service worker sets correct ' +
|
||||
'origin and referer headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, CROSS_SITE.hostname, 'POST',
|
||||
'fallback');
|
||||
assert_equals(result.origin, CROSS_SITE.origin, 'origin header');
|
||||
assert_equals(result.referer, CROSS_SITE.href, 'referer header');
|
||||
}, 'POST Navigation, cross-site with fallback service worker sets correct ' +
|
||||
'origin and referer headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, CROSS_SITE.hostname, 'GET',
|
||||
'navpreload');
|
||||
assert_equals(result.origin, 'not set', 'origin header');
|
||||
assert_equals(result.referer, CROSS_SITE.href, 'referer header');
|
||||
}, 'GET Navigation, cross-site with navpreload service worker sets correct ' +
|
||||
'origin and referer headers.');
|
||||
|
||||
// There is no POST test for navpreload since the feature only supports GET
|
||||
// requests.
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, CROSS_SITE.hostname, 'GET',
|
||||
'change-request');
|
||||
assert_equals(result.origin, 'not set', 'origin header');
|
||||
assert_equals(result.referer, script.href, 'referer header');
|
||||
}, 'GET Navigation, cross-site with service worker that changes the ' +
|
||||
'request sets correct origin and referer headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, CROSS_SITE.hostname, 'POST',
|
||||
'change-request');
|
||||
assert_equals(result.origin, SAME_ORIGIN.origin, 'origin header');
|
||||
assert_equals(result.referer, script.href, 'referer header');
|
||||
}, 'POST Navigation, cross-site with service worker that changes the ' +
|
||||
'request sets correct origin and referer headers.');
|
||||
|
||||
//
|
||||
// Sec-Fetch-* Headers (separated since not all browsers implement them)
|
||||
//
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_ORIGIN.hostname, 'GET',
|
||||
'no-sw');
|
||||
assert_equals(result['sec-fetch-site'], 'same-origin', 'sec-fetch-site header');
|
||||
assert_equals(result['sec-fetch-mode'], 'navigate', 'sec-fetch-mode header');
|
||||
assert_equals(result['sec-fetch-dest'], 'iframe', 'sec-fetch-dest header');
|
||||
}, 'GET Navigation, same-origin with no service worker sets correct ' +
|
||||
'sec-fetch headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_ORIGIN.hostname, 'POST',
|
||||
'no-sw');
|
||||
assert_equals(result['sec-fetch-site'], 'same-origin', 'sec-fetch-site header');
|
||||
assert_equals(result['sec-fetch-mode'], 'navigate', 'sec-fetch-mode header');
|
||||
assert_equals(result['sec-fetch-dest'], 'iframe', 'sec-fetch-dest header');
|
||||
}, 'POST Navigation, same-origin with no service worker sets correct ' +
|
||||
'sec-fetch headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_ORIGIN.hostname, 'GET',
|
||||
'passthrough');
|
||||
assert_equals(result['sec-fetch-site'], 'same-origin', 'sec-fetch-site header');
|
||||
assert_equals(result['sec-fetch-mode'], 'navigate', 'sec-fetch-mode header');
|
||||
assert_equals(result['sec-fetch-dest'], 'empty', 'sec-fetch-dest header');
|
||||
}, 'GET Navigation, same-origin with passthrough service worker sets correct ' +
|
||||
'sec-fetch headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_ORIGIN.hostname, 'POST',
|
||||
'passthrough');
|
||||
assert_equals(result['sec-fetch-site'], 'same-origin', 'sec-fetch-site header');
|
||||
assert_equals(result['sec-fetch-mode'], 'navigate', 'sec-fetch-mode header');
|
||||
assert_equals(result['sec-fetch-dest'], 'empty', 'sec-fetch-dest header');
|
||||
}, 'POST Navigation, same-origin with passthrough service worker sets correct ' +
|
||||
'sec-fetch headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_ORIGIN.hostname, 'GET',
|
||||
'fallback');
|
||||
assert_equals(result['sec-fetch-site'], 'same-origin', 'sec-fetch-site header');
|
||||
assert_equals(result['sec-fetch-mode'], 'navigate', 'sec-fetch-mode header');
|
||||
assert_equals(result['sec-fetch-dest'], 'iframe', 'sec-fetch-dest header');
|
||||
}, 'GET Navigation, same-origin with fallback service worker sets correct ' +
|
||||
'sec-fetch headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_ORIGIN.hostname, 'POST',
|
||||
'fallback');
|
||||
assert_equals(result['sec-fetch-site'], 'same-origin', 'sec-fetch-site header');
|
||||
assert_equals(result['sec-fetch-mode'], 'navigate', 'sec-fetch-mode header');
|
||||
assert_equals(result['sec-fetch-dest'], 'iframe', 'sec-fetch-dest header');
|
||||
}, 'POST Navigation, same-origin with fallback service worker sets correct ' +
|
||||
'sec-fetch headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_ORIGIN.hostname, 'GET',
|
||||
'navpreload');
|
||||
assert_equals(result['sec-fetch-site'], 'same-origin', 'sec-fetch-site header');
|
||||
assert_equals(result['sec-fetch-mode'], 'navigate', 'sec-fetch-mode header');
|
||||
assert_equals(result['sec-fetch-dest'], 'iframe', 'sec-fetch-dest header');
|
||||
}, 'GET Navigation, same-origin with navpreload service worker sets correct ' +
|
||||
'sec-fetch headers.');
|
||||
|
||||
// There is no POST test for navpreload since the feature only supports GET
|
||||
// requests.
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_ORIGIN.hostname, 'GET',
|
||||
'change-request');
|
||||
assert_equals(result['sec-fetch-site'], 'same-origin', 'sec-fetch-site header');
|
||||
assert_equals(result['sec-fetch-mode'], 'same-origin', 'sec-fetch-mode header');
|
||||
assert_equals(result['sec-fetch-dest'], 'empty', 'sec-fetch-dest header');
|
||||
}, 'GET Navigation, same-origin with service worker that changes the ' +
|
||||
'request sets correct sec-fetch headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_ORIGIN.hostname, 'POST',
|
||||
'change-request');
|
||||
assert_equals(result['sec-fetch-site'], 'same-origin', 'sec-fetch-site header');
|
||||
assert_equals(result['sec-fetch-mode'], 'same-origin', 'sec-fetch-mode header');
|
||||
assert_equals(result['sec-fetch-dest'], 'empty', 'sec-fetch-dest header');
|
||||
}, 'POST Navigation, same-origin with service worker that changes the ' +
|
||||
'request sets correct sec-fetch headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_SITE.hostname, 'GET',
|
||||
'no-sw');
|
||||
assert_equals(result['sec-fetch-site'], 'same-site', 'sec-fetch-site header');
|
||||
assert_equals(result['sec-fetch-mode'], 'navigate', 'sec-fetch-mode header');
|
||||
assert_equals(result['sec-fetch-dest'], 'iframe', 'sec-fetch-dest header');
|
||||
}, 'GET Navigation, same-site with no service worker sets correct ' +
|
||||
'sec-fetch headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_SITE.hostname, 'POST',
|
||||
'no-sw');
|
||||
assert_equals(result['sec-fetch-site'], 'same-site', 'sec-fetch-site header');
|
||||
assert_equals(result['sec-fetch-mode'], 'navigate', 'sec-fetch-mode header');
|
||||
assert_equals(result['sec-fetch-dest'], 'iframe', 'sec-fetch-dest header');
|
||||
}, 'POST Navigation, same-site with no service worker sets correct ' +
|
||||
'sec-fetch headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_SITE.hostname, 'GET',
|
||||
'passthrough');
|
||||
assert_equals(result['sec-fetch-site'], 'same-site', 'sec-fetch-site header');
|
||||
assert_equals(result['sec-fetch-mode'], 'navigate', 'sec-fetch-mode header');
|
||||
assert_equals(result['sec-fetch-dest'], 'empty', 'sec-fetch-dest header');
|
||||
}, 'GET Navigation, same-site with passthrough service worker sets correct ' +
|
||||
'sec-fetch headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_SITE.hostname, 'POST',
|
||||
'passthrough');
|
||||
assert_equals(result['sec-fetch-site'], 'same-site', 'sec-fetch-site header');
|
||||
assert_equals(result['sec-fetch-mode'], 'navigate', 'sec-fetch-mode header');
|
||||
assert_equals(result['sec-fetch-dest'], 'empty', 'sec-fetch-dest header');
|
||||
}, 'POST Navigation, same-site with passthrough service worker sets correct ' +
|
||||
'sec-fetch headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_SITE.hostname, 'GET',
|
||||
'fallback');
|
||||
assert_equals(result['sec-fetch-site'], 'same-site', 'sec-fetch-site header');
|
||||
assert_equals(result['sec-fetch-mode'], 'navigate', 'sec-fetch-mode header');
|
||||
assert_equals(result['sec-fetch-dest'], 'iframe', 'sec-fetch-dest header');
|
||||
}, 'GET Navigation, same-site with fallback service worker sets correct ' +
|
||||
'sec-fetch headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_SITE.hostname, 'POST',
|
||||
'fallback');
|
||||
assert_equals(result['sec-fetch-site'], 'same-site', 'sec-fetch-site header');
|
||||
assert_equals(result['sec-fetch-mode'], 'navigate', 'sec-fetch-mode header');
|
||||
assert_equals(result['sec-fetch-dest'], 'iframe', 'sec-fetch-dest header');
|
||||
}, 'POST Navigation, same-site with fallback service worker sets correct ' +
|
||||
'sec-fetch headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_SITE.hostname, 'GET',
|
||||
'navpreload');
|
||||
assert_equals(result['sec-fetch-site'], 'same-site', 'sec-fetch-site header');
|
||||
assert_equals(result['sec-fetch-mode'], 'navigate', 'sec-fetch-mode header');
|
||||
assert_equals(result['sec-fetch-dest'], 'iframe', 'sec-fetch-dest header');
|
||||
}, 'GET Navigation, same-site with navpreload service worker sets correct ' +
|
||||
'sec-fetch headers.');
|
||||
|
||||
// There is no POST test for navpreload since the feature only supports GET
|
||||
// requests.
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_SITE.hostname, 'GET',
|
||||
'change-request');
|
||||
assert_equals(result['sec-fetch-site'], 'same-origin', 'sec-fetch-site header');
|
||||
assert_equals(result['sec-fetch-mode'], 'same-origin', 'sec-fetch-mode header');
|
||||
assert_equals(result['sec-fetch-dest'], 'empty', 'sec-fetch-dest header');
|
||||
}, 'GET Navigation, same-site with service worker that changes the ' +
|
||||
'request sets correct sec-fetch headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, SAME_SITE.hostname, 'POST',
|
||||
'change-request');
|
||||
assert_equals(result['sec-fetch-site'], 'same-origin', 'sec-fetch-site header');
|
||||
assert_equals(result['sec-fetch-mode'], 'same-origin', 'sec-fetch-mode header');
|
||||
assert_equals(result['sec-fetch-dest'], 'empty', 'sec-fetch-dest header');
|
||||
}, 'POST Navigation, same-site with service worker that changes the ' +
|
||||
'request sets correct sec-fetch headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, CROSS_SITE.hostname, 'GET',
|
||||
'no-sw');
|
||||
assert_equals(result['sec-fetch-site'], 'cross-site', 'sec-fetch-site header');
|
||||
assert_equals(result['sec-fetch-mode'], 'navigate', 'sec-fetch-mode header');
|
||||
assert_equals(result['sec-fetch-dest'], 'iframe', 'sec-fetch-dest header');
|
||||
}, 'GET Navigation, cross-site with no service worker sets correct ' +
|
||||
'sec-fetch headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, CROSS_SITE.hostname, 'POST',
|
||||
'no-sw');
|
||||
assert_equals(result['sec-fetch-site'], 'cross-site', 'sec-fetch-site header');
|
||||
assert_equals(result['sec-fetch-mode'], 'navigate', 'sec-fetch-mode header');
|
||||
assert_equals(result['sec-fetch-dest'], 'iframe', 'sec-fetch-dest header');
|
||||
}, 'POST Navigation, cross-site with no service worker sets correct ' +
|
||||
'sec-fetch headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, CROSS_SITE.hostname, 'GET',
|
||||
'passthrough');
|
||||
assert_equals(result['sec-fetch-site'], 'cross-site', 'sec-fetch-site header');
|
||||
assert_equals(result['sec-fetch-mode'], 'navigate', 'sec-fetch-mode header');
|
||||
assert_equals(result['sec-fetch-dest'], 'empty', 'sec-fetch-dest header');
|
||||
}, 'GET Navigation, cross-site with passthrough service worker sets correct ' +
|
||||
'sec-fetch headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, CROSS_SITE.hostname, 'POST',
|
||||
'passthrough');
|
||||
assert_equals(result['sec-fetch-site'], 'cross-site', 'sec-fetch-site header');
|
||||
assert_equals(result['sec-fetch-mode'], 'navigate', 'sec-fetch-mode header');
|
||||
assert_equals(result['sec-fetch-dest'], 'empty', 'sec-fetch-dest header');
|
||||
}, 'POST Navigation, cross-site with passthrough service worker sets correct ' +
|
||||
'sec-fetch headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, CROSS_SITE.hostname, 'GET',
|
||||
'fallback');
|
||||
assert_equals(result['sec-fetch-site'], 'cross-site', 'sec-fetch-site header');
|
||||
assert_equals(result['sec-fetch-mode'], 'navigate', 'sec-fetch-mode header');
|
||||
assert_equals(result['sec-fetch-dest'], 'iframe', 'sec-fetch-dest header');
|
||||
}, 'GET Navigation, cross-site with fallback service worker sets correct ' +
|
||||
'sec-fetch headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, CROSS_SITE.hostname, 'POST',
|
||||
'fallback');
|
||||
assert_equals(result['sec-fetch-site'], 'cross-site', 'sec-fetch-site header');
|
||||
assert_equals(result['sec-fetch-mode'], 'navigate', 'sec-fetch-mode header');
|
||||
assert_equals(result['sec-fetch-dest'], 'iframe', 'sec-fetch-dest header');
|
||||
}, 'POST Navigation, cross-site with fallback service worker sets correct ' +
|
||||
'sec-fetch headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, CROSS_SITE.hostname, 'GET',
|
||||
'navpreload');
|
||||
assert_equals(result['sec-fetch-site'], 'cross-site', 'sec-fetch-site header');
|
||||
assert_equals(result['sec-fetch-mode'], 'navigate', 'sec-fetch-mode header');
|
||||
assert_equals(result['sec-fetch-dest'], 'iframe', 'sec-fetch-dest header');
|
||||
}, 'GET Navigation, cross-site with navpreload service worker sets correct ' +
|
||||
'sec-fetch headers.');
|
||||
|
||||
// There is no POST test for navpreload since the feature only supports GET
|
||||
// requests.
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, CROSS_SITE.hostname, 'GET',
|
||||
'change-request');
|
||||
assert_equals(result['sec-fetch-site'], 'same-origin', 'sec-fetch-site header');
|
||||
assert_equals(result['sec-fetch-mode'], 'same-origin', 'sec-fetch-mode header');
|
||||
assert_equals(result['sec-fetch-dest'], 'empty', 'sec-fetch-dest header');
|
||||
}, 'GET Navigation, cross-site with service worker that changes the ' +
|
||||
'request sets correct sec-fetch headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
const result = await post_and_get_headers(t, CROSS_SITE.hostname, 'POST',
|
||||
'change-request');
|
||||
assert_equals(result['sec-fetch-site'], 'same-origin', 'sec-fetch-site header');
|
||||
assert_equals(result['sec-fetch-mode'], 'same-origin', 'sec-fetch-mode header');
|
||||
assert_equals(result['sec-fetch-dest'], 'empty', 'sec-fetch-dest header');
|
||||
}, 'POST Navigation, cross-site with service worker that changes the ' +
|
||||
'request sets correct sec-fetch headers.');
|
||||
|
||||
promise_test(async t => {
|
||||
await registration.unregister();
|
||||
}, 'Cleanup service worker');
|
||||
|
||||
</script>
|
||||
</body>
|
@ -90,8 +90,12 @@ self.addEventListener('fetch', function(event) {
|
||||
var request = event.request;
|
||||
if (url) {
|
||||
request = new Request(url, init);
|
||||
} else if (params['change-request']) {
|
||||
request = new Request(request, init);
|
||||
}
|
||||
fetch(request).then(function(response) {
|
||||
const response_promise = params['navpreload'] ? event.preloadResponse
|
||||
: fetch(request);
|
||||
response_promise.then(function(response) {
|
||||
var expectedType = params['expected_type'];
|
||||
if (expectedType && response.type !== expectedType) {
|
||||
// Resolve a JSON object with a failure instead of rejecting
|
||||
|
2
third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/fetch-rewrite-worker.js.headers
vendored
Normal file
2
third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/fetch-rewrite-worker.js.headers
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
Content-Type: text/javascript
|
||||
Service-Worker-Allowed: /
|
12
third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/form-poster.html
vendored
Normal file
12
third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/form-poster.html
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<meta name="referrer" content="origin">
|
||||
<form method="POST" id="form"></form>
|
||||
<script>
|
||||
function onLoad() {
|
||||
const params = new URLSearchParams(self.location.search);
|
||||
const form = document.getElementById('form');
|
||||
form.action = decodeURIComponent(params.get('target'));
|
||||
form.submit();
|
||||
}
|
||||
self.addEventListener('load', onLoad);
|
||||
</script>
|
10
third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/location-setter.html
vendored
Normal file
10
third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/location-setter.html
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<meta name="referrer" content="origin">
|
||||
<script>
|
||||
function onLoad() {
|
||||
const params = new URLSearchParams(self.location.search);
|
||||
const target = decodeURIComponent(params.get('target'));
|
||||
self.location = target;
|
||||
}
|
||||
self.addEventListener('load', onLoad);
|
||||
</script>
|
19
third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/navigation-headers-server.py
vendored
Normal file
19
third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/navigation-headers-server.py
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
def main(request, response):
|
||||
response.status = (200, b"OK")
|
||||
response.headers.set(b"Content-Type", b"text/html")
|
||||
return b"""
|
||||
<script>
|
||||
self.addEventListener('load', evt => {
|
||||
self.parent.postMessage({
|
||||
origin: '%s',
|
||||
referer: '%s',
|
||||
'sec-fetch-site': '%s',
|
||||
'sec-fetch-mode': '%s',
|
||||
'sec-fetch-dest': '%s',
|
||||
});
|
||||
});
|
||||
</script>""" % (request.headers.get(
|
||||
b"origin", b"not set"), request.headers.get(b"referer", b"not set"),
|
||||
request.headers.get(b"sec-fetch-site", b"not set"),
|
||||
request.headers.get(b"sec-fetch-mode", b"not set"),
|
||||
request.headers.get(b"sec-fetch-dest", b"not set"))
|
22
third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/same-site-cookies-register.html
vendored
Normal file
22
third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/same-site-cookies-register.html
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8"/>
|
||||
<script>
|
||||
async function onLoad() {
|
||||
const scope = self.origin + '/cookies/resources/postToParent.py?with-sw';
|
||||
const script = './fetch-rewrite-worker.js';
|
||||
const reg = await navigator.serviceWorker.register(script, { scope: scope });
|
||||
await new Promise(resolve => {
|
||||
const worker = reg.installing;
|
||||
worker.addEventListener('statechange', evt => {
|
||||
if (worker.state === 'activated') {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
if (reg.navigationPreload) {
|
||||
await reg.navigationPreload.enable();
|
||||
}
|
||||
window.opener.postMessage({ type: 'SW-REGISTERED' }, '*');
|
||||
}
|
||||
self.addEventListener('load', onLoad);
|
||||
</script>
|
11
third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/same-site-cookies-unregister.html
vendored
Normal file
11
third_party/blink/web_tests/external/wpt/service-workers/service-worker/resources/same-site-cookies-unregister.html
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8"/>
|
||||
<script>
|
||||
async function onLoad() {
|
||||
const scope = self.origin + '/cookies/resources/postToParent.py?with-sw';
|
||||
const reg = await navigator.serviceWorker.getRegistration(scope);
|
||||
await reg.unregister();
|
||||
window.opener.postMessage({ type: 'SW-UNREGISTERED' }, '*');
|
||||
}
|
||||
self.addEventListener('load', onLoad);
|
||||
</script>
|
32
third_party/blink/web_tests/external/wpt/service-workers/service-worker/same-site-cookies.https-expected.txt
vendored
Normal file
32
third_party/blink/web_tests/external/wpt/service-workers/service-worker/same-site-cookies.https-expected.txt
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
This is a testharness.js-based test.
|
||||
PASS Setup service workers
|
||||
PASS same-origin, window.open with no service worker
|
||||
PASS same-origin, window.open with fallback
|
||||
PASS same-origin, window.open with passthrough
|
||||
PASS same-origin, window.open with change-request
|
||||
PASS same-origin, window.open with navpreload
|
||||
PASS same-site, window.open with no service worker
|
||||
PASS same-site, window.open with fallback
|
||||
PASS same-site, window.open with passthrough
|
||||
PASS same-site, window.open with change-request
|
||||
PASS same-site, window.open with navpreload
|
||||
PASS cross-site, window.open with no service worker
|
||||
PASS cross-site, window.open with fallback
|
||||
PASS cross-site, window.open with passthrough
|
||||
PASS cross-site, window.open with change-request
|
||||
PASS cross-site, window.open with navpreload
|
||||
PASS same-origin, form post with no service worker
|
||||
PASS same-origin, form post with fallback
|
||||
PASS same-origin, form post with passthrough
|
||||
PASS same-origin, form post with change-request
|
||||
PASS same-site, form post with no service worker
|
||||
PASS same-site, form post with fallback
|
||||
PASS same-site, form post with passthrough
|
||||
PASS same-site, form post with change-request
|
||||
FAIL cross-site, form post with no service worker assert_not_equals: Unspecified-SameSite cookies are not sent with cross-site requests. got disallowed value "COOKIE_VALUE"
|
||||
FAIL cross-site, form post with fallback assert_not_equals: Unspecified-SameSite cookies are not sent with cross-site requests. got disallowed value "COOKIE_VALUE"
|
||||
FAIL cross-site, form post with passthrough assert_not_equals: Unspecified-SameSite cookies are not sent with cross-site requests. got disallowed value "COOKIE_VALUE"
|
||||
PASS cross-site, form post with change-request
|
||||
PASS Cleanup service workers
|
||||
Harness: the test ran to completion.
|
||||
|
216
third_party/blink/web_tests/external/wpt/service-workers/service-worker/same-site-cookies.https.html
vendored
Normal file
216
third_party/blink/web_tests/external/wpt/service-workers/service-worker/same-site-cookies.https.html
vendored
Normal file
@ -0,0 +1,216 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="timeout" content="long">
|
||||
<title>Service Worker: Same-site cookie behavior</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/common/get-host-info.sub.js"></script>
|
||||
<script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script>
|
||||
<script src="/cookies/resources/cookie-helper.sub.js"></script>
|
||||
<body>
|
||||
<script>
|
||||
'use strict';
|
||||
async function unregister_service_worker(origin) {
|
||||
const w = window.open(origin +
|
||||
'/service-workers/service-worker/resources/same-site-cookies-unregister.html');
|
||||
try {
|
||||
await wait_for_message('SW-UNREGISTERED');
|
||||
} finally {
|
||||
w.close();
|
||||
}
|
||||
}
|
||||
|
||||
async function register_service_worker(origin) {
|
||||
const w = window.open(origin +
|
||||
'/service-workers/service-worker/resources/same-site-cookies-register.html');
|
||||
try {
|
||||
await wait_for_message('SW-REGISTERED');
|
||||
} finally {
|
||||
w.close();
|
||||
}
|
||||
}
|
||||
|
||||
async function run_test(t, origin, navaction, swaction, expected) {
|
||||
const value = 'COOKIE_VALUE';
|
||||
await resetSameSiteCookies(origin, value);
|
||||
if (swaction === 'navpreload') {
|
||||
assert_true('navigationPreload' in ServiceWorkerRegistration.prototype,
|
||||
'navigation preload must be supported');
|
||||
}
|
||||
const sw_param = swaction === 'no-sw' ? 'no-sw' : 'with-sw';
|
||||
let action_param = '';
|
||||
if (swaction === 'fallback') {
|
||||
action_param = '&ignore';
|
||||
} else if (swaction !== 'no-sw') {
|
||||
action_param = '&' + swaction;
|
||||
}
|
||||
const navpreload_param = swaction === 'navpreload' ? '&navpreload' : '';
|
||||
const change_request_param = swaction === 'change-request' ? '&change-request' : '';
|
||||
const target_string = origin + `/cookies/resources/postToParent.py?` +
|
||||
`${sw_param}${action_param}`
|
||||
const target_url = new URL(target_string);
|
||||
if (navaction === 'window.open') {
|
||||
const w = window.open(target_url);
|
||||
t.add_cleanup(() => w.close());
|
||||
} else if (navaction === 'form post') {
|
||||
const poster_url =
|
||||
`./resources/form-poster.html?target=${encodeURIComponent(target_url)}`;
|
||||
const w = window.open(poster_url);
|
||||
t.add_cleanup(() => w.close());
|
||||
}
|
||||
const result = await wait_for_message('COOKIES');
|
||||
verifySameSiteCookieState(expected, value, result.data,
|
||||
DomSameSiteStatus.SAME_SITE);
|
||||
}
|
||||
|
||||
promise_test(async t => {
|
||||
await register_service_worker(self.origin);
|
||||
await register_service_worker(SECURE_SUBDOMAIN_ORIGIN);
|
||||
await register_service_worker(SECURE_CROSS_SITE_ORIGIN);
|
||||
}, 'Setup service workers');
|
||||
|
||||
promise_test(t => {
|
||||
return run_test(t, self.origin, 'window.open', 'no-sw',
|
||||
SameSiteStatus.STRICT);
|
||||
}, 'same-origin, window.open with no service worker');
|
||||
|
||||
promise_test(t => {
|
||||
return run_test(t, self.origin, 'window.open', 'fallback',
|
||||
SameSiteStatus.STRICT);
|
||||
}, 'same-origin, window.open with fallback');
|
||||
|
||||
promise_test(t => {
|
||||
return run_test(t, self.origin, 'window.open', 'passthrough',
|
||||
SameSiteStatus.STRICT);
|
||||
}, 'same-origin, window.open with passthrough');
|
||||
|
||||
promise_test(t => {
|
||||
return run_test(t, self.origin, 'window.open', 'change-request',
|
||||
SameSiteStatus.STRICT);
|
||||
}, 'same-origin, window.open with change-request');
|
||||
|
||||
promise_test(t => {
|
||||
return run_test(t, self.origin, 'window.open', 'navpreload',
|
||||
SameSiteStatus.STRICT);
|
||||
}, 'same-origin, window.open with navpreload');
|
||||
|
||||
promise_test(t => {
|
||||
return run_test(t, SECURE_SUBDOMAIN_ORIGIN, 'window.open', 'no-sw',
|
||||
SameSiteStatus.STRICT);
|
||||
}, 'same-site, window.open with no service worker');
|
||||
|
||||
promise_test(t => {
|
||||
return run_test(t, SECURE_SUBDOMAIN_ORIGIN, 'window.open', 'fallback',
|
||||
SameSiteStatus.STRICT);
|
||||
}, 'same-site, window.open with fallback');
|
||||
|
||||
promise_test(t => {
|
||||
return run_test(t, SECURE_SUBDOMAIN_ORIGIN, 'window.open', 'passthrough',
|
||||
SameSiteStatus.STRICT);
|
||||
}, 'same-site, window.open with passthrough');
|
||||
|
||||
promise_test(t => {
|
||||
return run_test(t, SECURE_SUBDOMAIN_ORIGIN, 'window.open', 'change-request',
|
||||
SameSiteStatus.STRICT);
|
||||
}, 'same-site, window.open with change-request');
|
||||
|
||||
promise_test(t => {
|
||||
return run_test(t, SECURE_SUBDOMAIN_ORIGIN, 'window.open', 'navpreload',
|
||||
SameSiteStatus.STRICT);
|
||||
}, 'same-site, window.open with navpreload');
|
||||
|
||||
promise_test(t => {
|
||||
return run_test(t, SECURE_CROSS_SITE_ORIGIN, 'window.open', 'no-sw',
|
||||
SameSiteStatus.LAX);
|
||||
}, 'cross-site, window.open with no service worker');
|
||||
|
||||
promise_test(t => {
|
||||
return run_test(t, SECURE_CROSS_SITE_ORIGIN, 'window.open', 'fallback',
|
||||
SameSiteStatus.LAX);
|
||||
}, 'cross-site, window.open with fallback');
|
||||
|
||||
promise_test(t => {
|
||||
return run_test(t, SECURE_CROSS_SITE_ORIGIN, 'window.open', 'passthrough',
|
||||
SameSiteStatus.LAX);
|
||||
}, 'cross-site, window.open with passthrough');
|
||||
|
||||
promise_test(t => {
|
||||
return run_test(t, SECURE_CROSS_SITE_ORIGIN, 'window.open', 'change-request',
|
||||
SameSiteStatus.STRICT);
|
||||
}, 'cross-site, window.open with change-request');
|
||||
|
||||
promise_test(t => {
|
||||
return run_test(t, SECURE_CROSS_SITE_ORIGIN, 'window.open', 'navpreload',
|
||||
SameSiteStatus.LAX);
|
||||
}, 'cross-site, window.open with navpreload');
|
||||
|
||||
//
|
||||
// Form POST tests
|
||||
//
|
||||
promise_test(t => {
|
||||
return run_test(t, self.origin, 'form post', 'no-sw', SameSiteStatus.STRICT);
|
||||
}, 'same-origin, form post with no service worker');
|
||||
|
||||
promise_test(t => {
|
||||
return run_test(t, self.origin, 'form post', 'fallback',
|
||||
SameSiteStatus.STRICT);
|
||||
}, 'same-origin, form post with fallback');
|
||||
|
||||
promise_test(t => {
|
||||
return run_test(t, self.origin, 'form post', 'passthrough',
|
||||
SameSiteStatus.STRICT);
|
||||
}, 'same-origin, form post with passthrough');
|
||||
|
||||
promise_test(t => {
|
||||
return run_test(t, self.origin, 'form post', 'change-request',
|
||||
SameSiteStatus.STRICT);
|
||||
}, 'same-origin, form post with change-request');
|
||||
|
||||
promise_test(t => {
|
||||
return run_test(t, SECURE_SUBDOMAIN_ORIGIN, 'form post', 'no-sw',
|
||||
SameSiteStatus.STRICT);
|
||||
}, 'same-site, form post with no service worker');
|
||||
|
||||
promise_test(t => {
|
||||
return run_test(t, SECURE_SUBDOMAIN_ORIGIN, 'form post', 'fallback',
|
||||
SameSiteStatus.STRICT);
|
||||
}, 'same-site, form post with fallback');
|
||||
|
||||
promise_test(t => {
|
||||
return run_test(t, SECURE_SUBDOMAIN_ORIGIN, 'form post', 'passthrough',
|
||||
SameSiteStatus.STRICT);
|
||||
}, 'same-site, form post with passthrough');
|
||||
|
||||
promise_test(t => {
|
||||
return run_test(t, SECURE_SUBDOMAIN_ORIGIN, 'form post', 'change-request',
|
||||
SameSiteStatus.STRICT);
|
||||
}, 'same-site, form post with change-request');
|
||||
|
||||
promise_test(t => {
|
||||
return run_test(t, SECURE_CROSS_SITE_ORIGIN, 'form post', 'no-sw',
|
||||
SameSiteStatus.CROSS_SITE);
|
||||
}, 'cross-site, form post with no service worker');
|
||||
|
||||
promise_test(t => {
|
||||
return run_test(t, SECURE_CROSS_SITE_ORIGIN, 'form post', 'fallback',
|
||||
SameSiteStatus.CROSS_SITE);
|
||||
}, 'cross-site, form post with fallback');
|
||||
|
||||
promise_test(t => {
|
||||
return run_test(t, SECURE_CROSS_SITE_ORIGIN, 'form post', 'passthrough',
|
||||
SameSiteStatus.CROSS_SITE);
|
||||
}, 'cross-site, form post with passthrough');
|
||||
|
||||
promise_test(t => {
|
||||
return run_test(t, SECURE_CROSS_SITE_ORIGIN, 'form post', 'change-request',
|
||||
SameSiteStatus.STRICT);
|
||||
}, 'cross-site, form post with change-request');
|
||||
|
||||
promise_test(async t => {
|
||||
await unregister_service_worker(self.origin);
|
||||
await unregister_service_worker(SECURE_SUBDOMAIN_ORIGIN);
|
||||
await unregister_service_worker(SECURE_CROSS_SITE_ORIGIN);
|
||||
}, 'Cleanup service workers');
|
||||
|
||||
</script>
|
||||
</body>
|
Reference in New Issue
Block a user