From a009c49f938e7ae15ea5882e1b0f73bc01c7aca5 Mon Sep 17 00:00:00 2001 From: Eden Chuang Date: Mon, 23 Sep 2024 09:07:52 +0000 Subject: [PATCH] Bug 1843001 - Allow fetch() to localhost in Workers while network is offline. r=asuth,necko-reviewers,valentin Differential Revision: https://phabricator.services.mozilla.com/D198374 --- dom/fetch/FetchService.cpp | 37 +++++++++---- dom/fetch/FetchService.h | 2 + dom/serviceworkers/test/mochitest-common.toml | 7 +++ .../test/offline_fetch/index.html | 4 ++ .../test/offline_fetch/register.html | 16 ++++++ dom/serviceworkers/test/offline_fetch/sw.js | 3 ++ .../test/offline_fetch/unregister.html | 12 +++++ .../test/test_offline_localhost_fetch.html | 54 +++++++++++++++++++ 8 files changed, 124 insertions(+), 11 deletions(-) create mode 100644 dom/serviceworkers/test/offline_fetch/index.html create mode 100644 dom/serviceworkers/test/offline_fetch/register.html create mode 100644 dom/serviceworkers/test/offline_fetch/sw.js create mode 100644 dom/serviceworkers/test/offline_fetch/unregister.html create mode 100644 dom/serviceworkers/test/test_offline_localhost_fetch.html diff --git a/dom/fetch/FetchService.cpp b/dom/fetch/FetchService.cpp index 3d11221493fd..7e0836234960 100644 --- a/dom/fetch/FetchService.cpp +++ b/dom/fetch/FetchService.cpp @@ -297,6 +297,18 @@ RefPtr FetchService::FetchInstance::Fetch() { return mPromises; } +bool FetchService::FetchInstance::IsLocalHostFetch() const { + if (!mPrincipal) { + return false; + } + bool res; + nsresult rv = mPrincipal->GetIsLoopbackHost(&res); + if (NS_WARN_IF(NS_FAILED(rv))) { + return false; + } + return res; +} + void FetchService::FetchInstance::Cancel() { MOZ_ASSERT(XRE_IsParentProcess()); MOZ_ASSERT(NS_IsMainThread()); @@ -778,12 +790,15 @@ NS_IMETHODIMP FetchService::Observe(nsISupports* aSubject, const char* aTopic, mOffline = false; } else { mOffline = true; - // Network is offline, cancel running fetchs. - for (auto it = mFetchInstanceTable.begin(), end = mFetchInstanceTable.end(); - it != end; ++it) { - it->GetData()->Cancel(); - } - mFetchInstanceTable.Clear(); + // Network is offline, cancel the running fetch that is not to local server. + mFetchInstanceTable.RemoveIf([](auto& entry) { + bool res = entry.Data()->IsLocalHostFetch(); + if (res) { + return false; + } + entry.Data()->Cancel(); + return true; + }); } return NS_OK; } @@ -795,11 +810,6 @@ RefPtr FetchService::Fetch(FetchArgs&& aArgs) { FETCH_LOG(("FetchService::Fetch (%s)", aArgs.is() ? "NavigationPreload" : "WorkerFetch")); - if (mOffline) { - FETCH_LOG(("FetchService::Fetch network offline")); - return NetworkErrorResponse(NS_ERROR_OFFLINE, aArgs); - } - // Create FetchInstance RefPtr fetch = MakeRefPtr(); @@ -810,6 +820,11 @@ RefPtr FetchService::Fetch(FetchArgs&& aArgs) { return NetworkErrorResponse(rv, fetch->Args()); } + if (mOffline && !fetch->IsLocalHostFetch()) { + FETCH_LOG(("FetchService::Fetch network offline")); + return NetworkErrorResponse(NS_ERROR_OFFLINE, fetch->Args()); + } + // Call FetchInstance::Fetch() to start an asynchronous fetching. RefPtr promises = fetch->Fetch(); MOZ_ASSERT(promises); diff --git a/dom/fetch/FetchService.h b/dom/fetch/FetchService.h index f4a5d7943b8c..15faab4b0aa0 100644 --- a/dom/fetch/FetchService.h +++ b/dom/fetch/FetchService.h @@ -171,6 +171,8 @@ class FetchService final : public nsIObserver { void Cancel(); + bool IsLocalHostFetch() const; + /* FetchDriverObserver interface */ void OnResponseEnd(FetchDriverObserver::EndReason aReason, JS::Handle aReasonDetails) override; diff --git a/dom/serviceworkers/test/mochitest-common.toml b/dom/serviceworkers/test/mochitest-common.toml index b29e01f3742d..38856337d2c5 100644 --- a/dom/serviceworkers/test/mochitest-common.toml +++ b/dom/serviceworkers/test/mochitest-common.toml @@ -208,6 +208,10 @@ support-files = [ "onmessageerror_worker.js", "pref/fetch_nonexistent_file.html", "pref/intercept_nonexistent_file_sw.js", + "offline_fetch/register.html", + "offline_fetch/index.html", + "offline_fetch/unregister.html", + "offline_fetch/sw.js", ] ["test_abrupt_completion.html"] @@ -338,6 +342,9 @@ skip-if = ["os == 'linux' && bits == 64 && debug"] # Bug 1749068 ["test_not_intercept_plugin.html"] skip-if = ["serviceworker_e10s"] # leaks InterceptedHttpChannel and others things +["test_offline_localhost_fetch.html"] +skip-if = ["os == 'android'"] + ["test_onmessageerror.html"] skip-if = ["xorigin"] # Bug 1792790 diff --git a/dom/serviceworkers/test/offline_fetch/index.html b/dom/serviceworkers/test/offline_fetch/index.html new file mode 100644 index 000000000000..a435548443aa --- /dev/null +++ b/dom/serviceworkers/test/offline_fetch/index.html @@ -0,0 +1,4 @@ + + diff --git a/dom/serviceworkers/test/offline_fetch/register.html b/dom/serviceworkers/test/offline_fetch/register.html new file mode 100644 index 000000000000..667b2b712ec1 --- /dev/null +++ b/dom/serviceworkers/test/offline_fetch/register.html @@ -0,0 +1,16 @@ + + diff --git a/dom/serviceworkers/test/offline_fetch/sw.js b/dom/serviceworkers/test/offline_fetch/sw.js new file mode 100644 index 000000000000..f1221274ef93 --- /dev/null +++ b/dom/serviceworkers/test/offline_fetch/sw.js @@ -0,0 +1,3 @@ +self.addEventListener("fetch", function (event) { + event.respondWith(fetch(event.request)); +}); diff --git a/dom/serviceworkers/test/offline_fetch/unregister.html b/dom/serviceworkers/test/offline_fetch/unregister.html new file mode 100644 index 000000000000..1f13508fa700 --- /dev/null +++ b/dom/serviceworkers/test/offline_fetch/unregister.html @@ -0,0 +1,12 @@ + + diff --git a/dom/serviceworkers/test/test_offline_localhost_fetch.html b/dom/serviceworkers/test/test_offline_localhost_fetch.html new file mode 100644 index 000000000000..81b37f20eccb --- /dev/null +++ b/dom/serviceworkers/test/test_offline_localhost_fetch.html @@ -0,0 +1,54 @@ + + + + + Bug 1843001 + + + + + + + + +