Bug 1847358 part 2: create and use nsIBaseChannel to reduce code debt and better-encapsulate logic for range-requests on nsBaseChannel classes; r=dlrobertson,necko-reviewers,jesup

Differential Revision: https://phabricator.services.mozilla.com/D203379
This commit is contained in:
Thomas Wisniewski 2024-03-04 21:34:27 +00:00
Родитель 820f1c6cb8
Коммит 7c31f0e0ae
10 изменённых файлов: 114 добавлений и 49 удалений

Просмотреть файл

@ -13,6 +13,7 @@
#include "mozilla/dom/ReferrerInfo.h"
#include "nsIAsyncVerifyRedirectCallback.h"
#include "mozilla/dom/Document.h"
#include "nsIBaseChannel.h"
#include "nsICookieJarSettings.h"
#include "nsIFile.h"
#include "nsIInputStream.h"
@ -28,7 +29,6 @@
#include "nsIPipe.h"
#include "nsIRedirectHistoryEntry.h"
#include "nsBaseChannel.h"
#include "nsContentPolicyUtils.h"
#include "nsDataChannel.h"
#include "nsDataHandler.h"
@ -1100,13 +1100,10 @@ FetchDriver::OnStartRequest(nsIRequest* aRequest) {
// Should set a Content-Range header for blob scheme
// (https://fetch.spec.whatwg.org/#scheme-fetch)
nsAutoCString contentRange(VoidCString());
nsCOMPtr<nsIURI> uri;
channel->GetURI(getter_AddRefs(uri));
if (IsBlobURI(uri)) {
nsBaseChannel* bchan = static_cast<nsBaseChannel*>(channel.get());
MOZ_ASSERT(bchan);
Maybe<mozilla::net::ContentRange> range = bchan->GetContentRange();
if (range.isSome()) {
nsCOMPtr<nsIBaseChannel> baseChan = do_QueryInterface(mChannel);
if (baseChan) {
RefPtr<mozilla::net::ContentRange> range = baseChan->ContentRange();
if (range) {
range->AsHeader(contentRange);
}
}
@ -1122,6 +1119,8 @@ FetchDriver::OnStartRequest(nsIRequest* aRequest) {
MOZ_ASSERT(!result.Failed());
}
nsCOMPtr<nsIURI> uri;
channel->GetURI(getter_AddRefs(uri));
if (uri && uri->SchemeIs("data")) {
nsDataChannel* dchan = static_cast<nsDataChannel*>(channel.get());
MOZ_ASSERT(dchan);

Просмотреть файл

@ -489,9 +489,9 @@ nsresult BlobURLInputStream::StoreBlobImplStream(
// If a Range header was in the request then fetch/XHR will have set a
// ContentRange on the channel earlier so we may slice the blob now.
blobImpl->GetType(blobContentType);
const Maybe<mozilla::net::ContentRange>& contentRange =
mChannel->GetContentRange();
if (contentRange.isSome()) {
const RefPtr<mozilla::net::ContentRange>& contentRange =
mChannel->ContentRange();
if (contentRange) {
IgnoredErrorResult result;
uint64_t start = contentRange->Start();
uint64_t end = contentRange->End();

Просмотреть файл

@ -948,7 +948,7 @@ nsresult NS_GetBlobForBlobURISpec(const nsACString& aSpec,
}
// Blob requests may specify a range header. We parse, validate, and
// store that info here, and save it on the nsBaseChannel, where it
// store that info here, and save it on the nsIBaseChannel, where it
// can be accessed by BlobURLInputStream::StoreBlobImplStream.
nsresult NS_SetChannelContentRangeForBlobURI(nsIChannel* aChannel, nsIURI* aURI,
nsACString& aRangeHeader) {
@ -963,9 +963,8 @@ nsresult NS_SetChannelContentRangeForBlobURI(nsIChannel* aChannel, nsIURI* aURI,
if (result.Failed()) {
return NS_ERROR_NO_CONTENT;
}
nsBaseChannel* bchan = static_cast<nsBaseChannel*>(aChannel);
MOZ_ASSERT(bchan);
if (!bchan->SetContentRange(aRangeHeader, size)) {
nsCOMPtr<nsIBaseChannel> baseChan = do_QueryInterface(aChannel);
if (!baseChan || !baseChan->SetContentRangeFromHeader(aRangeHeader, size)) {
return NS_ERROR_NET_PARTIAL_TRANSFER;
}
return NS_OK;

Просмотреть файл

@ -49,6 +49,7 @@
#include "mozilla/StaticPrefs_privacy.h"
#include "mozilla/dom/ProgressEvent.h"
#include "nsDataChannel.h"
#include "nsIBaseChannel.h"
#include "nsIJARChannel.h"
#include "nsIJARURI.h"
#include "nsReadableUtils.h"
@ -864,14 +865,28 @@ bool XMLHttpRequestMainThread::IsDeniedCrossSiteCORSRequest() {
return false;
}
Maybe<mozilla::net::ContentRange>
bool XMLHttpRequestMainThread::BadContentRangeRequested() {
if (!mChannel) {
return false;
}
// Only nsIBaseChannel supports this
nsCOMPtr<nsIBaseChannel> baseChan = do_QueryInterface(mChannel);
if (!baseChan) {
return false;
}
// A bad range was requested if the channel has no content range
// despite the request specifying a range header.
return !baseChan->ContentRange() && mAuthorRequestHeaders.Has("range");
}
RefPtr<mozilla::net::ContentRange>
XMLHttpRequestMainThread::GetRequestedContentRange() const {
MOZ_ASSERT(mChannel);
nsBaseChannel* baseChan = static_cast<nsBaseChannel*>(mChannel.get());
nsCOMPtr<nsIBaseChannel> baseChan = do_QueryInterface(mChannel);
if (!baseChan) {
return mozilla::Nothing();
return nullptr;
}
return baseChan->GetContentRange();
return baseChan->ContentRange();
}
void XMLHttpRequestMainThread::GetContentRangeHeader(nsACString& out) const {
@ -879,8 +894,8 @@ void XMLHttpRequestMainThread::GetContentRangeHeader(nsACString& out) const {
out.SetIsVoid(true);
return;
}
Maybe<mozilla::net::ContentRange> range = GetRequestedContentRange();
if (range.isSome()) {
RefPtr<mozilla::net::ContentRange> range = GetRequestedContentRange();
if (range) {
range->AsHeader(out);
} else {
out.SetIsVoid(true);
@ -944,8 +959,7 @@ uint32_t XMLHttpRequestMainThread::GetStatus(ErrorResult& aRv) {
nsCOMPtr<nsIHttpChannel> httpChannel = GetCurrentHttpChannel();
if (!httpChannel) {
// Pretend like we got a 200/206 response, since our load was successful
return IsBlobURI(mRequestURL) && GetRequestedContentRange().isSome() ? 206
: 200;
return GetRequestedContentRange() ? 206 : 200;
}
uint32_t status;
@ -1956,8 +1970,7 @@ XMLHttpRequestMainThread::OnStartRequest(nsIRequest* request) {
// If we were asked for a bad range on a blob URL, but we're async,
// we should throw now in order to fire an error progress event.
if (IsBlobURI(mRequestURL) && GetRequestedContentRange().isNothing() &&
mAuthorRequestHeaders.Has("range")) {
if (BadContentRangeRequested()) {
return NS_ERROR_NET_PARTIAL_TRANSFER;
}

Просмотреть файл

@ -48,7 +48,6 @@
#include "mozilla/dom/XMLHttpRequestEventTarget.h"
#include "mozilla/dom/XMLHttpRequestString.h"
#include "mozilla/Encoding.h"
#include "nsBaseChannel.h"
#ifdef Status
/* Xlib headers insist on this for some reason... Nuke it because
@ -65,6 +64,10 @@ class nsILoadGroup;
namespace mozilla {
class ProfileChunkedBuffer;
namespace net {
class ContentRange;
}
namespace dom {
class DOMString;
@ -507,7 +510,8 @@ class XMLHttpRequestMainThread final : public XMLHttpRequest,
void AbortInternal(ErrorResult& aRv);
Maybe<mozilla::net::ContentRange> GetRequestedContentRange() const;
bool BadContentRangeRequested();
RefPtr<mozilla::net::ContentRange> GetRequestedContentRange() const;
void GetContentRangeHeader(nsACString&) const;
struct PendingEvent {

Просмотреть файл

@ -21,6 +21,8 @@ namespace mozilla::net {
class ContentRange {
private:
~ContentRange() = default;
uint64_t mStart{0};
uint64_t mEnd{0};
uint64_t mSize{0};
@ -34,6 +36,8 @@ class ContentRange {
: mStart(aStart), mEnd(aEnd), mSize(aSize) {}
ContentRange(const nsACString& aRangeHeader, uint64_t aSize);
void AsHeader(nsACString& aOutString) const;
NS_INLINE_DECL_REFCOUNTING(ContentRange)
};
} // namespace mozilla::net

Просмотреть файл

@ -18,6 +18,7 @@ XPIDL_SOURCES += [
"nsIAuthPromptCallback.idl",
"nsIAuthPromptProvider.idl",
"nsIBackgroundFileSaver.idl",
"nsIBaseChannel.idl",
"nsIBufferedStreams.idl",
"nsIByteRangeRequest.idl",
"nsICacheInfoChannel.idl",

Просмотреть файл

@ -8,7 +8,6 @@
#include "nsContentUtils.h"
#include "nsURLHelper.h"
#include "nsNetCID.h"
#include "nsMimeTypes.h"
#include "nsUnknownDecoder.h"
#include "nsIScriptSecurityManager.h"
#include "nsMimeTypes.h"
@ -302,6 +301,7 @@ NS_IMPL_RELEASE(nsBaseChannel)
NS_INTERFACE_MAP_BEGIN(nsBaseChannel)
NS_INTERFACE_MAP_ENTRY(nsIRequest)
NS_INTERFACE_MAP_ENTRY(nsIChannel)
NS_INTERFACE_MAP_ENTRY(nsIBaseChannel)
NS_INTERFACE_MAP_ENTRY(nsIThreadRetargetableRequest)
NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
NS_INTERFACE_MAP_ENTRY(nsITransportEventSink)
@ -966,3 +966,17 @@ NS_IMETHODIMP nsBaseChannel::GetCanceled(bool* aCanceled) {
void nsBaseChannel::SetupNeckoTarget() {
mNeckoTarget = GetMainThreadSerialEventTarget();
}
NS_IMETHODIMP nsBaseChannel::GetContentRange(
RefPtr<mozilla::net::ContentRange>* aRange) {
if (aRange) {
*aRange = mContentRange;
}
return NS_OK;
}
NS_IMETHODIMP nsBaseChannel::SetContentRange(
RefPtr<mozilla::net::ContentRange> aRange) {
mContentRange = aRange;
return NS_OK;
}

Просмотреть файл

@ -14,6 +14,7 @@
#include "mozilla/net/PrivateBrowsingChannel.h"
#include "nsHashPropertyBag.h"
#include "nsIAsyncVerifyRedirectCallback.h"
#include "nsIBaseChannel.h"
#include "nsIChannel.h"
#include "nsIInterfaceRequestor.h"
#include "nsILoadGroup.h"
@ -47,6 +48,7 @@ class nsICancelable;
class nsBaseChannel
: public nsHashPropertyBag,
public nsIBaseChannel,
public nsIChannel,
public nsIThreadRetargetableRequest,
public nsIInterfaceRequestor,
@ -59,6 +61,7 @@ class nsBaseChannel
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIREQUEST
NS_DECL_NSICHANNEL
NS_DECL_NSIBASECHANNEL
NS_DECL_NSIINTERFACEREQUESTOR
NS_DECL_NSITRANSPORTEVENTSINK
NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
@ -198,26 +201,6 @@ class nsBaseChannel
return mPumpingData || mWaitingOnAsyncRedirect;
}
// Blob requests may specify a range header. We must parse, validate, and
// store that info in a place where BlobURLInputStream::StoreBlobImplStream
// can access it.
const mozilla::Maybe<mozilla::net::ContentRange>& GetContentRange() const {
return mContentRange;
}
void SetContentRange(uint64_t aStart, uint64_t aEnd, uint64_t aSize) {
mContentRange.emplace(mozilla::net::ContentRange(aStart, aEnd, aSize));
}
bool SetContentRange(const nsACString& aRangeHeader, uint64_t aSize) {
auto range = mozilla::net::ContentRange(aRangeHeader, aSize);
if (!range.IsValid()) {
return false;
}
mContentRange.emplace(range);
return true;
}
// Helper function for querying the channel's notification callbacks.
template <class T>
void GetCallback(nsCOMPtr<T>& result) {
@ -308,7 +291,7 @@ class nsBaseChannel
bool mWaitingOnAsyncRedirect{false};
bool mOpenRedirectChannel{false};
uint32_t mRedirectFlags{0};
mozilla::Maybe<mozilla::net::ContentRange> mContentRange;
RefPtr<mozilla::net::ContentRange> mContentRange;
protected:
nsCString mContentType;

Просмотреть файл

@ -0,0 +1,48 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
%{C++
#include "mozilla/net/ContentRange.h"
%}
/**
* The nsIBaseChannel interface allows C++ code to query the interface
* of channels safely to gain access to content range functionality.
* This allows subclasses to optionally handle range-requests on their
* types using fetch/XMLHttpRequest even if they are not accessed via
* HTTP and therefore normally do not have support for headers.
*/
native ContentRangeRef(RefPtr<mozilla::net::ContentRange>);
[uuid(036d5cd7-9a53-40e3-9c72-c2ffaa15aa2b)]
interface nsIBaseChannel : nsISupports {
/**
* Used by fetch and XMLHttpRequest to get only the range specified in the
* Range request header (if given) for the response body (e.g, for blob URLs)
*/
attribute ContentRangeRef contentRange;
%{C++
RefPtr<mozilla::net::ContentRange> ContentRange() {
RefPtr<mozilla::net::ContentRange> range;
mozilla::Unused << GetContentRange(&range);
return range;
}
bool SetContentRangeFromHeader(const nsACString& aHeader, uint64_t aSize) {
RefPtr<mozilla::net::ContentRange> range =
new mozilla::net::ContentRange(aHeader, aSize);
if (!range->IsValid()) {
return false;
}
SetContentRange(range);
return true;
}
%}
};