зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1871378
- update Fetch algorithm to restrict Fetch body Size for keepalive request. r=necko-reviewers,edenchuang,kershaw
Differential Revision: https://phabricator.services.mozilla.com/D214245
This commit is contained in:
Родитель
1f2c55e2f7
Коммит
380c1efb91
|
@ -46,6 +46,7 @@
|
|||
|
||||
#include "BodyExtractor.h"
|
||||
#include "FetchChild.h"
|
||||
#include "FetchUtil.h"
|
||||
#include "FetchObserver.h"
|
||||
#include "InternalRequest.h"
|
||||
#include "InternalResponse.h"
|
||||
|
@ -603,6 +604,28 @@ already_AddRefed<Promise> FetchRequest(nsIGlobalObject* aGlobal,
|
|||
// keepalive is set to true, route the request through PFetch
|
||||
// We plan to route all main-thread fetch request through PFetch.
|
||||
// See Bug 1897129.
|
||||
|
||||
uint64_t bodyLength =
|
||||
internalRequest->BodyLength() > 0 ? internalRequest->BodyLength() : 0;
|
||||
|
||||
nsCOMPtr<nsILoadGroup> loadGroup =
|
||||
FetchUtil::GetLoadGroupFromGlobal(aGlobal);
|
||||
|
||||
if (loadGroup && !FetchUtil::IncrementPendingKeepaliveRequestSize(
|
||||
loadGroup, bodyLength)) {
|
||||
p->MaybeRejectWithTypeError<MSG_FETCH_FAILED>();
|
||||
return p.forget();
|
||||
};
|
||||
|
||||
if (!loadGroup) {
|
||||
// if there is no load group for this request ensure that the request
|
||||
// size does not exceed FETCH_KEEPALIVE_MAX_SIZE
|
||||
if (bodyLength > FETCH_KEEPALIVE_MAX_SIZE) {
|
||||
p->MaybeRejectWithTypeError<MSG_FETCH_FAILED>();
|
||||
return p.forget();
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<FetchChild> actor =
|
||||
FetchChild::CreateForMainThread(p, signalImpl, observer);
|
||||
if (!actor) {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "FetchChild.h"
|
||||
#include "FetchLog.h"
|
||||
#include "FetchObserver.h"
|
||||
#include "FetchUtil.h"
|
||||
#include "InternalResponse.h"
|
||||
#include "Request.h"
|
||||
#include "Response.h"
|
||||
|
@ -228,6 +229,7 @@ RefPtr<FetchChild> FetchChild::CreateForWorker(
|
|||
RefPtr<AbortSignalImpl> aSignalImpl, RefPtr<FetchObserver> aObserver) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(aWorkerPrivate);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
FETCH_LOG(("FetchChild::CreateForWorker [%p]", aWorkerPrivate));
|
||||
|
||||
RefPtr<FetchChild> actor = MakeRefPtr<FetchChild>(
|
||||
std::move(aPromise), std::move(aSignalImpl), std::move(aObserver));
|
||||
|
@ -254,6 +256,8 @@ RefPtr<FetchChild> FetchChild::CreateForMainThread(
|
|||
RefPtr<FetchChild> actor = MakeRefPtr<FetchChild>(
|
||||
std::move(aPromise), std::move(aSignalImpl), std::move(aObserver));
|
||||
actor->mIsKeepAliveRequest = true;
|
||||
FETCH_LOG(("FetchChild::CreateForMainThread actor[%p]", actor.get()));
|
||||
|
||||
return actor;
|
||||
}
|
||||
|
||||
|
@ -398,6 +402,12 @@ void FetchChild::RunAbortAlgorithm() {
|
|||
|
||||
void FetchChild::DoFetchOp(const FetchOpArgs& aArgs) {
|
||||
FETCH_LOG(("FetchChild::DoFetchOp [%p]", this));
|
||||
// we need to store this for keepalive request
|
||||
// as we need to update the load group during actor termination
|
||||
if (mIsKeepAliveRequest) {
|
||||
mKeepaliveRequestSize =
|
||||
aArgs.request().bodySize() > 0 ? aArgs.request().bodySize() : 0;
|
||||
}
|
||||
if (mSignalImpl) {
|
||||
if (mSignalImpl->Aborted()) {
|
||||
Unused << SendAbortFetchOp();
|
||||
|
@ -446,6 +456,22 @@ void FetchChild::Shutdown() {
|
|||
|
||||
void FetchChild::ActorDestroy(ActorDestroyReason aReason) {
|
||||
FETCH_LOG(("FetchChild::ActorDestroy [%p]", this));
|
||||
// for keepalive request decrement the pending keepalive count
|
||||
if (mIsKeepAliveRequest) {
|
||||
// we only support keepalive for main thread fetch requests
|
||||
// See Bug 1901759
|
||||
// For workers we need to dispatch a runnable to the main thread for
|
||||
// updating the loadgroup
|
||||
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mPromise->GetGlobalObject());
|
||||
nsCOMPtr<nsILoadGroup> loadGroup =
|
||||
FetchUtil::GetLoadGroupFromGlobal(mPromise->GetGlobalObject());
|
||||
if (loadGroup) {
|
||||
FetchUtil::DecrementPendingKeepaliveRequestSize(loadGroup,
|
||||
mKeepaliveRequestSize);
|
||||
}
|
||||
}
|
||||
mPromise = nullptr;
|
||||
mFetchObserver = nullptr;
|
||||
mSignalImpl = nullptr;
|
||||
|
|
|
@ -83,6 +83,7 @@ class FetchChild final : public PFetchChild, public AbortFollower {
|
|||
|
||||
RefPtr<ThreadSafeWorkerRef> mWorkerRef;
|
||||
bool mIsKeepAliveRequest{false};
|
||||
uint64_t mKeepaliveRequestSize{0};
|
||||
RefPtr<Promise> mPromise;
|
||||
RefPtr<AbortSignalImpl> mSignalImpl;
|
||||
RefPtr<FetchObserver> mFetchObserver;
|
||||
|
|
|
@ -76,6 +76,52 @@ static bool PushOverLine(nsACString::const_iterator& aStart,
|
|||
return false;
|
||||
}
|
||||
|
||||
// static
|
||||
bool FetchUtil::IncrementPendingKeepaliveRequestSize(
|
||||
nsILoadGroup* aLoadGroup, const uint64_t aBodyLength) {
|
||||
uint64_t pendingKeepaliveRequestSize = 0;
|
||||
MOZ_ASSERT(aLoadGroup);
|
||||
|
||||
aLoadGroup->GetTotalKeepAliveBytes(&pendingKeepaliveRequestSize);
|
||||
pendingKeepaliveRequestSize += aBodyLength;
|
||||
|
||||
if (pendingKeepaliveRequestSize > FETCH_KEEPALIVE_MAX_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aLoadGroup->SetTotalKeepAliveBytes(pendingKeepaliveRequestSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
void FetchUtil::DecrementPendingKeepaliveRequestSize(
|
||||
nsILoadGroup* aLoadGroup, const uint64_t aBodyLength) {
|
||||
MOZ_ASSERT(aLoadGroup);
|
||||
|
||||
uint64_t pendingKeepaliveRequestSize = 0;
|
||||
aLoadGroup->GetTotalKeepAliveBytes(&pendingKeepaliveRequestSize);
|
||||
MOZ_ASSERT(pendingKeepaliveRequestSize >= aBodyLength);
|
||||
pendingKeepaliveRequestSize -= aBodyLength;
|
||||
aLoadGroup->SetTotalKeepAliveBytes(pendingKeepaliveRequestSize);
|
||||
}
|
||||
|
||||
// static
|
||||
nsCOMPtr<nsILoadGroup> FetchUtil::GetLoadGroupFromGlobal(
|
||||
nsIGlobalObject* aGlobalObject) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
nsCOMPtr<nsILoadGroup> loadGroup = nullptr;
|
||||
auto* innerWindow = aGlobalObject->GetAsInnerWindow();
|
||||
|
||||
if (innerWindow) {
|
||||
Document* doc = innerWindow->GetExtantDoc();
|
||||
if (doc) {
|
||||
loadGroup = doc->GetDocumentLoadGroup();
|
||||
}
|
||||
}
|
||||
|
||||
return loadGroup;
|
||||
}
|
||||
|
||||
// static
|
||||
bool FetchUtil::ExtractHeader(nsACString::const_iterator& aStart,
|
||||
nsACString::const_iterator& aEnd,
|
||||
|
|
|
@ -24,6 +24,8 @@ class Document;
|
|||
class InternalRequest;
|
||||
class WorkerPrivate;
|
||||
|
||||
#define FETCH_KEEPALIVE_MAX_SIZE 65536
|
||||
|
||||
class FetchUtil final {
|
||||
private:
|
||||
FetchUtil() = delete;
|
||||
|
@ -76,6 +78,23 @@ class FetchUtil final {
|
|||
* untyped 'size_t' instead of Gecko 'nsresult'.
|
||||
*/
|
||||
static void ReportJSStreamError(JSContext* aCx, size_t aErrorCode);
|
||||
|
||||
/**
|
||||
* Implements fetch spec
|
||||
* https://fetch.spec.whatwg.org/#http-network-or-cache-fetch for
|
||||
* bounding the keepalive request size
|
||||
*/
|
||||
static bool IncrementPendingKeepaliveRequestSize(nsILoadGroup* aLoadGroup,
|
||||
const uint64_t aBodyLength);
|
||||
|
||||
static void DecrementPendingKeepaliveRequestSize(nsILoadGroup* aLoadGroup,
|
||||
const uint64_t aBodyLength);
|
||||
|
||||
/**
|
||||
* Wrapper to fetch loadgroup from the global object
|
||||
*/
|
||||
static nsCOMPtr<nsILoadGroup> GetLoadGroupFromGlobal(
|
||||
nsIGlobalObject* aGlobal);
|
||||
};
|
||||
|
||||
} // namespace mozilla::dom
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#define mozilla_dom_InternalRequest_h
|
||||
|
||||
#include "mozilla/dom/HeadersBinding.h"
|
||||
#include "mozilla/dom/InternalResponse.h"
|
||||
#include "mozilla/dom/InternalHeaders.h"
|
||||
#include "mozilla/dom/RequestBinding.h"
|
||||
#include "mozilla/dom/SafeRefPtr.h"
|
||||
|
@ -306,6 +307,8 @@ class InternalRequest final : public AtomicSafeRefCounted<InternalRequest> {
|
|||
}
|
||||
}
|
||||
|
||||
int64_t BodyLength() const { return mBodyLength; }
|
||||
|
||||
void SetBodyBlobURISpec(nsACString& aBlobURISpec) {
|
||||
mBodyBlobURISpec = aBlobURISpec;
|
||||
}
|
||||
|
@ -434,7 +437,7 @@ class InternalRequest final : public AtomicSafeRefCounted<InternalRequest> {
|
|||
nsCString mBodyBlobURISpec;
|
||||
nsString mBodyLocalPath;
|
||||
nsCOMPtr<nsIInputStream> mBodyStream;
|
||||
int64_t mBodyLength;
|
||||
int64_t mBodyLength{InternalResponse::UNKNOWN_BODY_SIZE};
|
||||
|
||||
nsCString mPreferredAlternativeDataType;
|
||||
|
||||
|
|
|
@ -66,6 +66,13 @@ interface nsILoadGroup : nsIRequest
|
|||
*/
|
||||
readonly attribute nsISimpleEnumerator requests;
|
||||
|
||||
/**
|
||||
* Sum total of content length of all pending keepalive
|
||||
* requests in the fetch group group.
|
||||
* See https://fetch.spec.whatwg.org/#ref-for-request-keepalive-flag%E2%91%A0
|
||||
*/
|
||||
attribute unsigned long long totalKeepAliveBytes;
|
||||
|
||||
/**
|
||||
* Returns the count of "active" requests (ie. requests without the
|
||||
* LOAD_BACKGROUND bit set).
|
||||
|
|
|
@ -659,6 +659,19 @@ nsLoadGroup::GetRequests(nsISimpleEnumerator** aRequests) {
|
|||
return NS_NewArrayEnumerator(aRequests, requests, NS_GET_IID(nsIRequest));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLoadGroup::GetTotalKeepAliveBytes(uint64_t* aTotalKeepAliveBytes) {
|
||||
MOZ_ASSERT(aTotalKeepAliveBytes);
|
||||
*aTotalKeepAliveBytes = mPendingKeepaliveRequestSize;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLoadGroup::SetTotalKeepAliveBytes(uint64_t aTotalKeepAliveBytes) {
|
||||
mPendingKeepaliveRequestSize = aTotalKeepAliveBytes;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsLoadGroup::SetGroupObserver(nsIRequestObserver* aObserver) {
|
||||
SetGroupObserver(aObserver, false);
|
||||
|
|
|
@ -99,6 +99,9 @@ class nsLoadGroup : public nsILoadGroup,
|
|||
bool mExternalRequestContext{false};
|
||||
bool mNotifyObserverAboutBackgroundRequests{false};
|
||||
|
||||
// size of requests with keepalive flag for this load group
|
||||
uint64_t mPendingKeepaliveRequestSize{0};
|
||||
|
||||
/* Telemetry */
|
||||
mozilla::TimeStamp mDefaultRequestCreationTime;
|
||||
uint32_t mTimedRequests{0};
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
[request-keepalive-quota.html]
|
||||
[A Keep-Alive fetch() with a body over the Quota Limit should reject.]
|
||||
expected: FAIL
|
||||
|
||||
[A Keep-Alive fetch() should not be allowed if the Quota is used up.]
|
||||
expected: FAIL
|
||||
|
||||
[A Keep-Alive fetch() should return only its allocated Quota upon promise resolution.]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[request-keepalive-quota.html?slow-2]
|
||||
[Request Keepalive Quota Tests]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[request-keepalive-quota.html?fast]
|
||||
[Request Keepalive Quota Tests]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[request-keepalive-quota.html?slow-3]
|
||||
[Request Keepalive Quota Tests]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[request-keepalive-quota.html?slow-1]
|
||||
[Request Keepalive Quota Tests]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[request-keepalive-quota.html?include=slow-2]
|
||||
[A Keep-Alive fetch() should return only its allocated Quota upon promise resolution.]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[request-keepalive-quota.html?include=fast]
|
||||
[A Keep-Alive fetch() with a body over the Quota Limit should reject.]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[request-keepalive-quota.html?include=slow-3]
|
||||
expected:
|
||||
if (os == "android") and fission: [TIMEOUT, OK]
|
||||
[A Keep-Alive fetch() should not be allowed if the Quota is used up.]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[request-keepalive-quota.html?include=slow-1]
|
Загрузка…
Ссылка в новой задаче