Bug 1722759 - Make devtools network panel to display images that are loaded by the image cache r=necko-reviewers,dragana,tnikkel,bomsy

Differential Revision: https://phabricator.services.mozilla.com/D121122
This commit is contained in:
Sean Feng 2021-10-12 22:30:46 +00:00
parent 0b3a97aaf8
commit d275bc2c1f
6 changed files with 139 additions and 5 deletions

View File

@ -45,11 +45,17 @@ class NetworkEventContentWatcher {
this.onUpdated = onUpdated;
this.httpFailedOpeningRequest = this.httpFailedOpeningRequest.bind(this);
this.httpOnImageCacheResponse = this.httpOnImageCacheResponse.bind(this);
Services.obs.addObserver(
this.httpFailedOpeningRequest,
"http-on-failed-opening-request"
);
Services.obs.addObserver(
this.httpOnImageCacheResponse,
"http-on-image-cache-response"
);
}
get conn() {
@ -107,6 +113,71 @@ class NetworkEventContentWatcher {
NetworkUtils.fetchRequestHeadersAndCookies(channel, actor, {});
}
httpOnImageCacheResponse(subject, topic) {
if (
topic != "http-on-image-cache-response" ||
!(subject instanceof Ci.nsIHttpChannel)
) {
return;
}
const channel = subject.QueryInterface(Ci.nsIHttpChannel);
const event = NetworkUtils.createNetworkEvent(channel, {
fromCache: true,
});
const actor = new NetworkEventActor(
this,
{
onNetworkEventUpdate: this.onNetworkEventUpdatedForImageCache.bind(
this
),
onNetworkEventDestroy: this.onNetworkEventDestroyed.bind(this),
},
event
);
this.targetActor.manage(actor);
const resource = actor.asResource();
this._networkEvents.set(resource.resourceId, {
resourceId: resource.resourceId,
resourceType: resource.resourceType,
types: [],
resourceUpdates: {},
});
// The channel we get here is a dummy channel and no real internet
// connection has been made, thus some dummy values need to be
// set.
resource.status = 200;
resource.statusText = "OK";
resource.totalTime = 0;
resource.mimeType = channel.contentType;
resource.contentSize = channel.contentLength;
this.onAvailable([resource]);
NetworkUtils.fetchRequestHeadersAndCookies(channel, actor, {});
}
onNetworkEventUpdatedForImageCache(updateResource) {
const networkEvent = this._networkEvents.get(updateResource.resourceId);
if (!networkEvent) {
return;
}
const { resourceId, resourceType, resourceUpdates, types } = networkEvent;
resourceUpdates[`${updateResource.updateType}Available`] = true;
types.push(updateResource.updateType);
if (types.includes("requestHeaders")) {
this.onUpdated([{ resourceType, resourceId, resourceUpdates }]);
}
}
onNetworkEventUpdated(updateResource) {
const networkEvent = this._networkEvents.get(updateResource.resourceId);
@ -135,6 +206,11 @@ class NetworkEventContentWatcher {
this.httpFailedOpeningRequest,
"http-on-failed-opening-request"
);
Services.obs.removeObserver(
this.httpOnImageCacheResponse,
"http-on-image-cache-response"
);
}
}

View File

@ -1869,6 +1869,35 @@ bool imgLoader::ValidateRequestWithNewChannel(
return true;
}
void imgLoader::NotifyObserversForCachedImage(
imgCacheEntry* aEntry, imgRequest* request, nsIURI* aURI,
nsIReferrerInfo* aReferrerInfo, Document* aLoadingDocument,
nsIPrincipal* aTriggeringPrincipal, CORSMode aCORSMode) {
nsCOMPtr<nsIChannel> newChannel;
bool forcePrincipalCheck;
nsresult rv =
NewImageChannel(getter_AddRefs(newChannel), &forcePrincipalCheck, aURI,
nullptr, aCORSMode, aReferrerInfo, nullptr, 0,
nsIContentPolicy::TYPE_INTERNAL_IMAGE,
aTriggeringPrincipal, aLoadingDocument, mRespectPrivacy);
if (NS_FAILED(rv)) {
return;
}
RefPtr<HttpBaseChannel> httpBaseChannel = do_QueryObject(newChannel);
if (httpBaseChannel) {
httpBaseChannel->SetDummyChannelForImageCache();
newChannel->SetContentType(nsDependentCString(request->GetMimeType()));
RefPtr<mozilla::image::Image> image = request->GetImage();
if (image) {
newChannel->SetContentLength(aEntry->GetDataSize());
}
nsCOMPtr<nsIObserverService> obsService = services::GetObserverService();
obsService->NotifyObservers(newChannel, "http-on-image-cache-response",
nullptr);
}
}
bool imgLoader::ValidateEntry(
imgCacheEntry* aEntry, nsIURI* aURI, nsIURI* aInitialDocumentURI,
nsIReferrerInfo* aReferrerInfo, nsILoadGroup* aLoadGroup,
@ -2017,6 +2046,12 @@ bool imgLoader::ValidateEntry(
aNewChannelCreated);
}
if (!validateRequest) {
NotifyObserversForCachedImage(aEntry, request, aURI, aReferrerInfo,
aLoadingDocument, aTriggeringPrincipal,
aCORSMode);
}
return !validateRequest;
}

View File

@ -369,6 +369,12 @@ class imgLoader final : public imgILoader,
imgRequestProxy** aProxyRequest, nsIPrincipal* aLoadingPrincipal,
mozilla::CORSMode, bool aLinkPreload, bool* aNewChannelCreated);
void NotifyObserversForCachedImage(imgCacheEntry* aEntry, imgRequest* request,
nsIURI* aURI,
nsIReferrerInfo* aReferrerInfo,
mozilla::dom::Document* aLoadingDocument,
nsIPrincipal* aLoadingPrincipal,
mozilla::CORSMode);
// aURI may be different from imgRequest's URI in the case of blob URIs, as we
// can share requests with different URIs.
nsresult CreateNewProxyForRequest(imgRequest* aRequest, nsIURI* aURI,

View File

@ -209,7 +209,8 @@ HttpBaseChannel::HttpBaseChannel()
mCachedOpaqueResponseBlockingPref(
StaticPrefs::browser_opaqueResponseBlocking()),
mBlockOpaqueResponseAfterSniff(false),
mCheckIsOpaqueResponseAllowedAfterSniff(false) {
mCheckIsOpaqueResponseAllowedAfterSniff(false),
mDummyChannelForImageCache(false) {
StoreApplyConversion(true);
StoreAllowSTS(true);
StoreTracingEnabled(true);
@ -609,7 +610,7 @@ HttpBaseChannel::GetContentType(nsACString& aContentType) {
NS_IMETHODIMP
HttpBaseChannel::SetContentType(const nsACString& aContentType) {
if (mListener || LoadWasOpened()) {
if (mListener || LoadWasOpened() || mDummyChannelForImageCache) {
if (!mResponseHead) return NS_ERROR_NOT_AVAILABLE;
nsAutoCString contentTypeBuf, charsetBuf;
@ -757,8 +758,13 @@ HttpBaseChannel::GetContentLength(int64_t* aContentLength) {
NS_IMETHODIMP
HttpBaseChannel::SetContentLength(int64_t value) {
MOZ_ASSERT_UNREACHABLE("HttpBaseChannel::SetContentLength");
return NS_ERROR_NOT_IMPLEMENTED;
if (!mDummyChannelForImageCache) {
MOZ_ASSERT_UNREACHABLE("HttpBaseChannel::SetContentLength");
return NS_ERROR_NOT_IMPLEMENTED;
}
MOZ_ASSERT(mResponseHead);
mResponseHead->SetContentLength(value);
return NS_OK;
}
NS_IMETHODIMP
@ -5653,5 +5659,12 @@ bool HttpBaseChannel::Http3Allowed() const {
LoadAllowHttp3();
}
void HttpBaseChannel::SetDummyChannelForImageCache() {
mDummyChannelForImageCache = true;
MOZ_ASSERT(!mResponseHead,
"SetDummyChannelForImageCache should only be called once");
mResponseHead = MakeUnique<nsHttpResponseHead>();
}
} // namespace net
} // namespace mozilla

View File

@ -415,6 +415,8 @@ class HttpBaseChannel : public nsHashPropertyBag,
return mResponseTrailers.get();
}
void SetDummyChannelForImageCache();
const NetAddr& GetSelfAddr() { return mSelfAddr; }
const NetAddr& GetPeerAddr() { return mPeerAddr; }
@ -891,6 +893,7 @@ class HttpBaseChannel : public nsHashPropertyBag,
const bool mCachedOpaqueResponseBlockingPref;
bool mBlockOpaqueResponseAfterSniff;
bool mCheckIsOpaqueResponseAllowedAfterSniff;
bool mDummyChannelForImageCache;
// clang-format off
MOZ_ATOMIC_BITFIELDS(mAtomicBitfields3, 8, (

View File

@ -187,7 +187,8 @@ nsresult nsObserverService::FilterHttpOnTopics(const char* aTopic) {
if (mozilla::net::IsNeckoChild() && !strncmp(aTopic, "http-on-", 8) &&
strcmp(aTopic, "http-on-failed-opening-request") &&
strcmp(aTopic, "http-on-opening-request") &&
strcmp(aTopic, "http-on-stop-request")) {
strcmp(aTopic, "http-on-stop-request") &&
strcmp(aTopic, "http-on-image-cache-response")) {
nsCOMPtr<nsIConsoleService> console(
do_GetService(NS_CONSOLESERVICE_CONTRACTID));
nsCOMPtr<nsIScriptError> error(