/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set sw=2 ts=4 sts=2 et cin: */ /* 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/. */
// // Log module for nsILoadGroup logging... // // To enable logging (see prlog.h for full details): // // set MOZ_LOG=LoadGroup:5 // set MOZ_LOG_FILE=network.log // // This enables LogLevel::Debug level information and places all output in // the file network.log. // static LazyLogModule gLoadGroupLog("LoadGroup"); #undef LOG #define LOG(args) MOZ_LOG(gLoadGroupLog, mozilla::LogLevel::Debug, args)
staticbool AppendRequestsToArray(PLDHashTable* aTable,
nsTArray<nsIRequest*>* aArray) { for (auto iter = aTable->Iter(); !iter.Done(); iter.Next()) { auto* e = static_cast<RequestMapEntry*>(iter.Get());
nsIRequest* request = e->mKey;
MOZ_DIAGNOSTIC_ASSERT(request, "Null key in mRequests PLDHashTable entry");
// XXX(Bug 1631371) Check if this should use a fallible operation as it // pretended earlier.
aArray->AppendElement(request);
NS_ADDREF(request);
}
if (aArray->Length() != aTable->EntryCount()) { for (uint32_t i = 0, len = aArray->Length(); i < len; ++i) {
NS_RELEASE((*aArray)[i]);
} returnfalse;
} returntrue;
}
NS_ASSERTION(NS_FAILED(status), "shouldn't cancel with a success code");
nsresult rv;
uint32_t count = mRequests.EntryCount();
AutoTArray<nsIRequest*, 8> requests;
if (!AppendRequestsToArray(&mRequests, &requests)) { return NS_ERROR_OUT_OF_MEMORY;
}
// set the load group status to our cancel status while we cancel // all our requests...once the cancel is done, we'll reset it... //
mStatus = status;
// Set the flag indicating that the loadgroup is being canceled... This // prevents any new channels from being added during the operation. //
mIsCanceling = true;
NS_ASSERTION(request, "NULL request found in list.");
if (!mRequests.Search(request)) { // |request| was removed already // We need to null out the entry in the request array so we don't try // to notify the observers for this request.
nsCOMPtr<nsIRequest> request = dont_AddRef(requests.ElementAt(count));
requests.ElementAt(count) = nullptr;
// Cancel the request...
rv = request->CancelWithReason(status, mCanceledReason);
// Remember the first failure and return it... if (NS_FAILED(rv) && NS_SUCCEEDED(firstError)) firstError = rv;
if (NS_FAILED(RemoveRequestFromHashtable(request, status))) { // It's possible that request->Cancel causes the request to be removed // from the loadgroup causing RemoveRequestFromHashtable to fail. // In that case we shouldn't call NotifyRemovalObservers or decrement // mForegroundCount since that has already happened.
nsCOMPtr<nsIRequest> request = dont_AddRef(requests.ElementAt(count));
requests.ElementAt(count) = nullptr;
if (mRequestContext) {
Unused << mRequestContext->CancelTailPendingRequests(status);
}
#ifdefined(DEBUG)
NS_ASSERTION(mRequests.EntryCount() == 0, "Request list is not empty.");
NS_ASSERTION(mForegroundCount == 0, "Foreground URLs are active."); #endif
if (!AppendRequestsToArray(&mRequests, &requests)) { return NS_ERROR_OUT_OF_MEMORY;
}
firstError = NS_OK; // // Operate the elements from back to front so that if items get // get removed from the list it won't affect our iteration // while (count > 0) {
nsCOMPtr<nsIRequest> request = dont_AddRef(requests.ElementAt(--count));
NS_ASSERTION(request, "NULL request found in list."); if (!request) continue;
if (!AppendRequestsToArray(&mRequests, &requests)) { return NS_ERROR_OUT_OF_MEMORY;
}
firstError = NS_OK; // // Operate the elements from back to front so that if items get // get removed from the list it won't affect our iteration // while (count > 0) {
nsCOMPtr<nsIRequest> request = dont_AddRef(requests.ElementAt(--count));
NS_ASSERTION(request, "NULL request found in list."); if (!request) continue;
mDefaultLoadRequest = aRequest; // Inherit the group load flags from the default load request if (mDefaultLoadRequest) {
mDefaultLoadRequest->GetLoadFlags(&mLoadFlags); // // Mask off any bits that are not part of the nsIRequest flags. // in particular, nsIChannel::LOAD_DOCUMENT_URI... //
mLoadFlags &= nsIRequest::LOAD_REQUESTMASK;
nsCOMPtr<nsITimedChannel> timedChannel = do_QueryInterface(aRequest);
mDefaultLoadIsTimed = timedChannel != nullptr; if (mDefaultLoadIsTimed) {
timedChannel->GetChannelCreation(&mDefaultRequestCreationTime);
}
} // Else, do not change the group's load flags (see bug 95981) return NS_OK;
}
NS_ASSERTION(!mRequests.Search(request), "Entry added to loadgroup twice, don't do that");
// // Do not add the channel, if the loadgroup is being canceled... // if (mIsCanceling) {
LOG(
("LOADGROUP [%p]: AddChannel() ABORTED because LoadGroup is" " being canceled!!\n", this));
return NS_BINDING_ABORTED;
}
nsLoadFlags flags; // if the request is the default load request or if the default load // request is null, then the load group should inherit its load flags from // the request, but also we need to enforce defaultLoadFlags. if (mDefaultLoadRequest == request || !mDefaultLoadRequest) {
rv = MergeDefaultLoadFlags(request, flags);
} else {
rv = MergeLoadFlags(request, flags);
} if (NS_FAILED(rv)) return rv;
// // Add the request to the list of active requests... //
if (mPriority != 0) RescheduleRequest(request, mPriority);
bool foreground = !(flags & nsIRequest::LOAD_BACKGROUND); if (foreground) { // Update the count of foreground URIs..
mForegroundCount += 1;
}
if (foreground || mNotifyObserverAboutBackgroundRequests) { // // Fire the OnStartRequest notification out to the observer... // // If the notification fails then DO NOT add the request to // the load group. //
nsCOMPtr<nsIRequestObserver> observer = do_QueryReferent(mObserver); if (observer) {
LOG(
("LOADGROUP [%p]: Firing OnStartRequest for request %p." "(foreground count=%d).\n", this, request, mForegroundCount));
rv = observer->OnStartRequest(request); if (NS_FAILED(rv)) {
LOG(("LOADGROUP [%p]: OnStartRequest for request %p FAILED.\n", this,
request)); // // The URI load has been canceled by the observer. Clean up // the damage... //
mRequests.Remove(request);
rv = NS_OK;
if (foreground) {
mForegroundCount -= 1;
}
}
}
// Ensure that we're part of our loadgroup while pending if (foreground && mForegroundCount == 1 && mLoadGroup) {
mLoadGroup->AddRequest(this, nullptr);
}
}
return rv;
}
NS_IMETHODIMP
nsLoadGroup::RemoveRequest(nsIRequest* request, nsISupports* ctxt,
nsresult aStatus) { // Make sure we have a owning reference to the request we're about // to remove.
nsCOMPtr<nsIRequest> kungFuDeathGrip(request);
// // Remove the request from the group. If this fails, it means that // the request was *not* in the group so do not update the foreground // count or it will get messed up... // auto* entry = static_cast<RequestMapEntry*>(mRequests.Search(request));
if (!entry) {
LOG(("LOADGROUP [%p]: Unable to remove request %p. Not in group!\n", this,
request));
return NS_ERROR_FAILURE;
}
mRequests.RemoveEntry(entry);
// Cache the status of mDefaultLoadRequest, It'll be used later in // TelemetryReport. if (request == mDefaultLoadRequest) {
mDefaultStatus = aStatus;
}
// Collect telemetry stats only when default request is a timed channel. // Don't include failed requests in the timing statistics. if (mDefaultLoadIsTimed && NS_SUCCEEDED(aStatus)) {
nsCOMPtr<nsITimedChannel> timedChannel = do_QueryInterface(request); if (timedChannel) { // Figure out if this request was served from the cache
++mTimedRequests;
TimeStamp timeStamp;
rv = timedChannel->GetCacheReadStart(&timeStamp); if (NS_SUCCEEDED(rv) && !timeStamp.IsNull()) {
++mCachedRequests;
}
if (foreground || mNotifyObserverAboutBackgroundRequests) { // Fire the OnStopRequest out to the observer...
nsCOMPtr<nsIRequestObserver> observer = do_QueryReferent(mObserver); if (observer) {
LOG(
("LOADGROUP [%p]: Firing OnStopRequest for request %p." "(foreground count=%d).\n", this, request, mForegroundCount));
rv = observer->OnStopRequest(request, aStatus);
if (NS_FAILED(rv)) {
LOG(("LOADGROUP [%p]: OnStopRequest for request %p FAILED.\n", this,
request));
}
}
// If that was the last request -> remove ourselves from loadgroup if (foreground && mForegroundCount == 0 && mLoadGroup) {
mLoadGroup->RemoveRequest(this, nullptr, aStatus);
}
}
NS_IMETHODIMP
nsLoadGroup::GetRootLoadGroup(nsILoadGroup** aRootLoadGroup) { // first recursively try the root load group of our parent
nsCOMPtr<nsILoadGroupChild> ancestor = do_QueryReferent(mParentLoadGroup); if (ancestor) return ancestor->GetRootLoadGroup(aRootLoadGroup);
// next recursively try the root load group of our own load grop
ancestor = do_QueryInterface(mLoadGroup); if (ancestor) return ancestor->GetRootLoadGroup(aRootLoadGroup);
// finally just return this
*aRootLoadGroup = do_AddRef(this).take(); return NS_OK;
}
void nsLoadGroup::TelemetryReport() { // We should only report HTTP_PAGE_* telemetry if the defaultRequest was // actually successful. if (mDefaultLoadIsTimed && NS_SUCCEEDED(mDefaultStatus)) {
Telemetry::Accumulate(Telemetry::HTTP_REQUEST_PER_PAGE, mTimedRequests); if (mTimedRequests) {
Telemetry::Accumulate(Telemetry::HTTP_REQUEST_PER_PAGE_FROM_CACHE,
mCachedRequests * 100 / mTimedRequests);
}
}
TimeStamp asyncOpen;
rv = aTimedChannel->GetAsyncOpen(&asyncOpen); // We do not check !asyncOpen.IsNull() bellow, prevent ASSERTIONs this way if (NS_FAILED(rv) || asyncOpen.IsNull()) return;
TimeStamp cacheReadStart;
rv = aTimedChannel->GetCacheReadStart(&cacheReadStart); if (NS_FAILED(rv)) return;
TimeStamp cacheReadEnd;
rv = aTimedChannel->GetCacheReadEnd(&cacheReadEnd); if (NS_FAILED(rv)) return;
TimeStamp domainLookupStart;
rv = aTimedChannel->GetDomainLookupStart(&domainLookupStart); if (NS_FAILED(rv)) return;
TimeStamp domainLookupEnd;
rv = aTimedChannel->GetDomainLookupEnd(&domainLookupEnd); if (NS_FAILED(rv)) return;
TimeStamp connectStart;
rv = aTimedChannel->GetConnectStart(&connectStart); if (NS_FAILED(rv)) return;
TimeStamp secureConnectionStart;
rv = aTimedChannel->GetSecureConnectionStart(&secureConnectionStart); if (NS_FAILED(rv)) return;
TimeStamp connectEnd;
rv = aTimedChannel->GetConnectEnd(&connectEnd); if (NS_FAILED(rv)) return;
TimeStamp requestStart;
rv = aTimedChannel->GetRequestStart(&requestStart); if (NS_FAILED(rv)) return;
TimeStamp responseStart;
rv = aTimedChannel->GetResponseStart(&responseStart); if (NS_FAILED(rv)) return;
TimeStamp responseEnd;
rv = aTimedChannel->GetResponseEnd(&responseEnd); if (NS_FAILED(rv)) return; #ifndef ANDROID bool useHttp3 = false; #endif bool supportHttp3 = false;
nsCOMPtr<nsIHttpChannelInternal> httpChannel =
do_QueryInterface(aTimedChannel); if (httpChannel) {
uint32_t major;
uint32_t minor; if (NS_SUCCEEDED(httpChannel->GetResponseVersion(&major, &minor))) { #ifndef ANDROID
useHttp3 = major == 3; #endif if (major == 2) { if (NS_FAILED(httpChannel->GetSupportsHTTP3(&supportHttp3))) {
supportHttp3 = false;
}
}
}
}
// Glean instrumentation of metrics previously collected via Geckoview // Streaming. if (!domainLookupStart.IsNull()) { if (aDefaultRequest) {
mozilla::glean::network::dns_start.AccumulateRawDuration(
domainLookupStart - asyncOpen); if (!domainLookupEnd.IsNull()) {
mozilla::glean::network::dns_end.AccumulateRawDuration(
domainLookupEnd - domainLookupStart);
}
} #ifndef ANDROID else {
mozilla::glean::network::sub_dns_start.AccumulateRawDuration(
domainLookupStart - asyncOpen); if (!domainLookupEnd.IsNull()) {
mozilla::glean::network::sub_dns_end.AccumulateRawDuration(
domainLookupEnd - domainLookupStart);
}
} #endif
} if (!connectEnd.IsNull()) { if (!connectStart.IsNull()) { if (aDefaultRequest) {
mozilla::glean::network::tcp_connection.AccumulateRawDuration(
connectEnd - connectStart);
} #ifndef ANDROID else {
mozilla::glean::network::sub_tcp_connection.AccumulateRawDuration(
connectEnd - connectStart);
} #endif
} if (!secureConnectionStart.IsNull()) { if (aDefaultRequest) {
mozilla::glean::network::tls_handshake.AccumulateRawDuration(
connectEnd - secureConnectionStart);
} #ifndef ANDROID else {
mozilla::glean::network::sub_tls_handshake.AccumulateRawDuration(
connectEnd - secureConnectionStart);
} #endif
}
} if (!requestStart.IsNull() && !responseEnd.IsNull()) { if (aDefaultRequest) {
mozilla::glean::network::open_to_first_sent.AccumulateRawDuration(
requestStart - asyncOpen);
mozilla::glean::network::first_sent_to_last_received
.AccumulateRawDuration(responseEnd - requestStart);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.