netwerk/base/src/nsLoadGroup.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/netwerk/base/src/nsLoadGroup.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1179 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* vim: set sw=4 ts=4 sts=4 et cin: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "mozilla/DebugOnly.h"
    1.11 +
    1.12 +#include "nsLoadGroup.h"
    1.13 +
    1.14 +#include "nsArrayEnumerator.h"
    1.15 +#include "nsCOMArray.h"
    1.16 +#include "nsCOMPtr.h"
    1.17 +#include "prlog.h"
    1.18 +#include "nsString.h"
    1.19 +#include "nsTArray.h"
    1.20 +#include "mozilla/Atomics.h"
    1.21 +#include "mozilla/Telemetry.h"
    1.22 +#include "nsAutoPtr.h"
    1.23 +#include "mozilla/net/PSpdyPush.h"
    1.24 +#include "nsITimedChannel.h"
    1.25 +#include "nsIInterfaceRequestor.h"
    1.26 +#include "nsIRequestObserver.h"
    1.27 +#include "CacheObserver.h"
    1.28 +#include "MainThreadUtils.h"
    1.29 +
    1.30 +using namespace mozilla;
    1.31 +using namespace mozilla::net;
    1.32 +
    1.33 +#if defined(PR_LOGGING)
    1.34 +//
    1.35 +// Log module for nsILoadGroup logging...
    1.36 +//
    1.37 +// To enable logging (see prlog.h for full details):
    1.38 +//
    1.39 +//    set NSPR_LOG_MODULES=LoadGroup:5
    1.40 +//    set NSPR_LOG_FILE=nspr.log
    1.41 +//
    1.42 +// this enables PR_LOG_DEBUG level information and places all output in
    1.43 +// the file nspr.log
    1.44 +//
    1.45 +static PRLogModuleInfo* gLoadGroupLog = nullptr;
    1.46 +#endif
    1.47 +
    1.48 +#undef LOG
    1.49 +#define LOG(args) PR_LOG(gLoadGroupLog, PR_LOG_DEBUG, args)
    1.50 +
    1.51 +////////////////////////////////////////////////////////////////////////////////
    1.52 +
    1.53 +class RequestMapEntry : public PLDHashEntryHdr
    1.54 +{
    1.55 +public:
    1.56 +    RequestMapEntry(nsIRequest *aRequest) :
    1.57 +        mKey(aRequest)
    1.58 +    {
    1.59 +    }
    1.60 +
    1.61 +    nsCOMPtr<nsIRequest> mKey;
    1.62 +};
    1.63 +
    1.64 +static bool
    1.65 +RequestHashMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *entry,
    1.66 +                      const void *key)
    1.67 +{
    1.68 +    const RequestMapEntry *e =
    1.69 +        static_cast<const RequestMapEntry *>(entry);
    1.70 +    const nsIRequest *request = static_cast<const nsIRequest *>(key);
    1.71 +
    1.72 +    return e->mKey == request;
    1.73 +}
    1.74 +
    1.75 +static void
    1.76 +RequestHashClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
    1.77 +{
    1.78 +    RequestMapEntry *e = static_cast<RequestMapEntry *>(entry);
    1.79 +
    1.80 +    // An entry is being cleared, let the entry do its own cleanup.
    1.81 +    e->~RequestMapEntry();
    1.82 +}
    1.83 +
    1.84 +static bool
    1.85 +RequestHashInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
    1.86 +                     const void *key)
    1.87 +{
    1.88 +    const nsIRequest *const_request = static_cast<const nsIRequest *>(key);
    1.89 +    nsIRequest *request = const_cast<nsIRequest *>(const_request);
    1.90 +
    1.91 +    // Initialize the entry with placement new
    1.92 +    new (entry) RequestMapEntry(request);
    1.93 +    return true;
    1.94 +}
    1.95 +
    1.96 +
    1.97 +static void
    1.98 +RescheduleRequest(nsIRequest *aRequest, int32_t delta)
    1.99 +{
   1.100 +    nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(aRequest);
   1.101 +    if (p)
   1.102 +        p->AdjustPriority(delta);
   1.103 +}
   1.104 +
   1.105 +static PLDHashOperator
   1.106 +RescheduleRequests(PLDHashTable *table, PLDHashEntryHdr *hdr,
   1.107 +                   uint32_t number, void *arg)
   1.108 +{
   1.109 +    RequestMapEntry *e = static_cast<RequestMapEntry *>(hdr);
   1.110 +    int32_t *delta = static_cast<int32_t *>(arg);
   1.111 +
   1.112 +    RescheduleRequest(e->mKey, *delta);
   1.113 +    return PL_DHASH_NEXT;
   1.114 +}
   1.115 +
   1.116 +
   1.117 +nsLoadGroup::nsLoadGroup(nsISupports* outer)
   1.118 +    : mForegroundCount(0)
   1.119 +    , mLoadFlags(LOAD_NORMAL)
   1.120 +    , mDefaultLoadFlags(0)
   1.121 +    , mStatus(NS_OK)
   1.122 +    , mPriority(PRIORITY_NORMAL)
   1.123 +    , mIsCanceling(false)
   1.124 +    , mDefaultLoadIsTimed(false)
   1.125 +    , mTimedRequests(0)
   1.126 +    , mCachedRequests(0)
   1.127 +    , mTimedNonCachedRequestsUntilOnEndPageLoad(0)
   1.128 +{
   1.129 +    NS_INIT_AGGREGATED(outer);
   1.130 +
   1.131 +#if defined(PR_LOGGING)
   1.132 +    // Initialize the global PRLogModule for nsILoadGroup logging
   1.133 +    if (nullptr == gLoadGroupLog)
   1.134 +        gLoadGroupLog = PR_NewLogModule("LoadGroup");
   1.135 +#endif
   1.136 +
   1.137 +    LOG(("LOADGROUP [%x]: Created.\n", this));
   1.138 +
   1.139 +    // Initialize the ops in the hash to null to make sure we get
   1.140 +    // consistent errors if someone fails to call ::Init() on an
   1.141 +    // nsLoadGroup.
   1.142 +    mRequests.ops = nullptr;
   1.143 +}
   1.144 +
   1.145 +nsLoadGroup::~nsLoadGroup()
   1.146 +{
   1.147 +    DebugOnly<nsresult> rv = Cancel(NS_BINDING_ABORTED);
   1.148 +    NS_ASSERTION(NS_SUCCEEDED(rv), "Cancel failed");
   1.149 +
   1.150 +    if (mRequests.ops) {
   1.151 +        PL_DHashTableFinish(&mRequests);
   1.152 +    }
   1.153 +
   1.154 +    mDefaultLoadRequest = 0;
   1.155 +
   1.156 +    LOG(("LOADGROUP [%x]: Destroyed.\n", this));
   1.157 +}
   1.158 +
   1.159 +
   1.160 +////////////////////////////////////////////////////////////////////////////////
   1.161 +// nsISupports methods:
   1.162 +
   1.163 +NS_IMPL_AGGREGATED(nsLoadGroup)
   1.164 +NS_INTERFACE_MAP_BEGIN_AGGREGATED(nsLoadGroup)
   1.165 +    NS_INTERFACE_MAP_ENTRY(nsILoadGroup)
   1.166 +    NS_INTERFACE_MAP_ENTRY(nsPILoadGroupInternal)
   1.167 +    NS_INTERFACE_MAP_ENTRY(nsILoadGroupChild)
   1.168 +    NS_INTERFACE_MAP_ENTRY(nsIRequest)
   1.169 +    NS_INTERFACE_MAP_ENTRY(nsISupportsPriority)
   1.170 +    NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
   1.171 +NS_INTERFACE_MAP_END
   1.172 +
   1.173 +////////////////////////////////////////////////////////////////////////////////
   1.174 +// nsIRequest methods:
   1.175 +
   1.176 +NS_IMETHODIMP
   1.177 +nsLoadGroup::GetName(nsACString &result)
   1.178 +{
   1.179 +    // XXX is this the right "name" for a load group?
   1.180 +
   1.181 +    if (!mDefaultLoadRequest) {
   1.182 +        result.Truncate();
   1.183 +        return NS_OK;
   1.184 +    }
   1.185 +    
   1.186 +    return mDefaultLoadRequest->GetName(result);
   1.187 +}
   1.188 +
   1.189 +NS_IMETHODIMP
   1.190 +nsLoadGroup::IsPending(bool *aResult)
   1.191 +{
   1.192 +    *aResult = (mForegroundCount > 0) ? true : false;
   1.193 +    return NS_OK;
   1.194 +}
   1.195 +
   1.196 +NS_IMETHODIMP
   1.197 +nsLoadGroup::GetStatus(nsresult *status)
   1.198 +{
   1.199 +    if (NS_SUCCEEDED(mStatus) && mDefaultLoadRequest)
   1.200 +        return mDefaultLoadRequest->GetStatus(status);
   1.201 +    
   1.202 +    *status = mStatus;
   1.203 +    return NS_OK; 
   1.204 +}
   1.205 +
   1.206 +// PLDHashTable enumeration callback that appends strong references to
   1.207 +// all nsIRequest to an nsTArray<nsIRequest*>.
   1.208 +static PLDHashOperator
   1.209 +AppendRequestsToArray(PLDHashTable *table, PLDHashEntryHdr *hdr,
   1.210 +                      uint32_t number, void *arg)
   1.211 +{
   1.212 +    RequestMapEntry *e = static_cast<RequestMapEntry *>(hdr);
   1.213 +    nsTArray<nsIRequest*> *array = static_cast<nsTArray<nsIRequest*> *>(arg);
   1.214 +
   1.215 +    nsIRequest *request = e->mKey;
   1.216 +    NS_ASSERTION(request, "What? Null key in pldhash entry?");
   1.217 +
   1.218 +    bool ok = array->AppendElement(request) != nullptr;
   1.219 +
   1.220 +    if (!ok) {
   1.221 +        return PL_DHASH_STOP;
   1.222 +    }
   1.223 +
   1.224 +    NS_ADDREF(request);
   1.225 +
   1.226 +    return PL_DHASH_NEXT;
   1.227 +}
   1.228 +
   1.229 +NS_IMETHODIMP
   1.230 +nsLoadGroup::Cancel(nsresult status)
   1.231 +{
   1.232 +    MOZ_ASSERT(NS_IsMainThread());
   1.233 +
   1.234 +    NS_ASSERTION(NS_FAILED(status), "shouldn't cancel with a success code");
   1.235 +    nsresult rv;
   1.236 +    uint32_t count = mRequests.entryCount;
   1.237 +
   1.238 +    nsAutoTArray<nsIRequest*, 8> requests;
   1.239 +
   1.240 +    PL_DHashTableEnumerate(&mRequests, AppendRequestsToArray,
   1.241 +                           static_cast<nsTArray<nsIRequest*> *>(&requests));
   1.242 +
   1.243 +    if (requests.Length() != count) {
   1.244 +        for (uint32_t i = 0, len = requests.Length(); i < len; ++i) {
   1.245 +            NS_RELEASE(requests[i]);
   1.246 +        }
   1.247 +
   1.248 +        return NS_ERROR_OUT_OF_MEMORY;
   1.249 +    }
   1.250 +
   1.251 +    // set the load group status to our cancel status while we cancel 
   1.252 +    // all our requests...once the cancel is done, we'll reset it...
   1.253 +    //
   1.254 +    mStatus = status;
   1.255 +
   1.256 +    // Set the flag indicating that the loadgroup is being canceled...  This
   1.257 +    // prevents any new channels from being added during the operation.
   1.258 +    //
   1.259 +    mIsCanceling = true;
   1.260 +
   1.261 +    nsresult firstError = NS_OK;
   1.262 +
   1.263 +    while (count > 0) {
   1.264 +        nsIRequest* request = requests.ElementAt(--count);
   1.265 +
   1.266 +        NS_ASSERTION(request, "NULL request found in list.");
   1.267 +
   1.268 +        RequestMapEntry *entry =
   1.269 +            static_cast<RequestMapEntry *>
   1.270 +                       (PL_DHashTableOperate(&mRequests, request,
   1.271 +                                                PL_DHASH_LOOKUP));
   1.272 +
   1.273 +        if (PL_DHASH_ENTRY_IS_FREE(entry)) {
   1.274 +            // |request| was removed already
   1.275 +
   1.276 +            NS_RELEASE(request);
   1.277 +
   1.278 +            continue;
   1.279 +        }
   1.280 +
   1.281 +#if defined(PR_LOGGING)
   1.282 +        nsAutoCString nameStr;
   1.283 +        request->GetName(nameStr);
   1.284 +        LOG(("LOADGROUP [%x]: Canceling request %x %s.\n",
   1.285 +             this, request, nameStr.get()));
   1.286 +#endif
   1.287 +
   1.288 +        //
   1.289 +        // Remove the request from the load group...  This may cause
   1.290 +        // the OnStopRequest notification to fire...
   1.291 +        //
   1.292 +        // XXX: What should the context be?
   1.293 +        //
   1.294 +        (void)RemoveRequest(request, nullptr, status);
   1.295 +
   1.296 +        // Cancel the request...
   1.297 +        rv = request->Cancel(status);
   1.298 +
   1.299 +        // Remember the first failure and return it...
   1.300 +        if (NS_FAILED(rv) && NS_SUCCEEDED(firstError))
   1.301 +            firstError = rv;
   1.302 +
   1.303 +        NS_RELEASE(request);
   1.304 +    }
   1.305 +
   1.306 +#if defined(DEBUG)
   1.307 +    NS_ASSERTION(mRequests.entryCount == 0, "Request list is not empty.");
   1.308 +    NS_ASSERTION(mForegroundCount == 0, "Foreground URLs are active.");
   1.309 +#endif
   1.310 +
   1.311 +    mStatus = NS_OK;
   1.312 +    mIsCanceling = false;
   1.313 +
   1.314 +    return firstError;
   1.315 +}
   1.316 +
   1.317 +
   1.318 +NS_IMETHODIMP
   1.319 +nsLoadGroup::Suspend()
   1.320 +{
   1.321 +    nsresult rv, firstError;
   1.322 +    uint32_t count = mRequests.entryCount;
   1.323 +
   1.324 +    nsAutoTArray<nsIRequest*, 8> requests;
   1.325 +
   1.326 +    PL_DHashTableEnumerate(&mRequests, AppendRequestsToArray,
   1.327 +                           static_cast<nsTArray<nsIRequest*> *>(&requests));
   1.328 +
   1.329 +    if (requests.Length() != count) {
   1.330 +        for (uint32_t i = 0, len = requests.Length(); i < len; ++i) {
   1.331 +            NS_RELEASE(requests[i]);
   1.332 +        }
   1.333 +
   1.334 +        return NS_ERROR_OUT_OF_MEMORY;
   1.335 +    }
   1.336 +
   1.337 +    firstError = NS_OK;
   1.338 +    //
   1.339 +    // Operate the elements from back to front so that if items get
   1.340 +    // get removed from the list it won't affect our iteration
   1.341 +    //
   1.342 +    while (count > 0) {
   1.343 +        nsIRequest* request = requests.ElementAt(--count);
   1.344 +
   1.345 +        NS_ASSERTION(request, "NULL request found in list.");
   1.346 +        if (!request)
   1.347 +            continue;
   1.348 +
   1.349 +#if defined(PR_LOGGING)
   1.350 +        nsAutoCString nameStr;
   1.351 +        request->GetName(nameStr);
   1.352 +        LOG(("LOADGROUP [%x]: Suspending request %x %s.\n",
   1.353 +            this, request, nameStr.get()));
   1.354 +#endif
   1.355 +
   1.356 +        // Suspend the request...
   1.357 +        rv = request->Suspend();
   1.358 +
   1.359 +        // Remember the first failure and return it...
   1.360 +        if (NS_FAILED(rv) && NS_SUCCEEDED(firstError))
   1.361 +            firstError = rv;
   1.362 +
   1.363 +        NS_RELEASE(request);
   1.364 +    }
   1.365 +
   1.366 +    return firstError;
   1.367 +}
   1.368 +
   1.369 +
   1.370 +NS_IMETHODIMP
   1.371 +nsLoadGroup::Resume()
   1.372 +{
   1.373 +    nsresult rv, firstError;
   1.374 +    uint32_t count = mRequests.entryCount;
   1.375 +
   1.376 +    nsAutoTArray<nsIRequest*, 8> requests;
   1.377 +
   1.378 +    PL_DHashTableEnumerate(&mRequests, AppendRequestsToArray,
   1.379 +                           static_cast<nsTArray<nsIRequest*> *>(&requests));
   1.380 +
   1.381 +    if (requests.Length() != count) {
   1.382 +        for (uint32_t i = 0, len = requests.Length(); i < len; ++i) {
   1.383 +            NS_RELEASE(requests[i]);
   1.384 +        }
   1.385 +
   1.386 +        return NS_ERROR_OUT_OF_MEMORY;
   1.387 +    }
   1.388 +
   1.389 +    firstError = NS_OK;
   1.390 +    //
   1.391 +    // Operate the elements from back to front so that if items get
   1.392 +    // get removed from the list it won't affect our iteration
   1.393 +    //
   1.394 +    while (count > 0) {
   1.395 +        nsIRequest* request = requests.ElementAt(--count);
   1.396 +
   1.397 +        NS_ASSERTION(request, "NULL request found in list.");
   1.398 +        if (!request)
   1.399 +            continue;
   1.400 +
   1.401 +#if defined(PR_LOGGING)
   1.402 +        nsAutoCString nameStr;
   1.403 +        request->GetName(nameStr);
   1.404 +        LOG(("LOADGROUP [%x]: Resuming request %x %s.\n",
   1.405 +            this, request, nameStr.get()));
   1.406 +#endif
   1.407 +
   1.408 +        // Resume the request...
   1.409 +        rv = request->Resume();
   1.410 +
   1.411 +        // Remember the first failure and return it...
   1.412 +        if (NS_FAILED(rv) && NS_SUCCEEDED(firstError))
   1.413 +            firstError = rv;
   1.414 +
   1.415 +        NS_RELEASE(request);
   1.416 +    }
   1.417 +
   1.418 +    return firstError;
   1.419 +}
   1.420 +
   1.421 +NS_IMETHODIMP
   1.422 +nsLoadGroup::GetLoadFlags(uint32_t *aLoadFlags)
   1.423 +{
   1.424 +    *aLoadFlags = mLoadFlags;
   1.425 +    return NS_OK;
   1.426 +}
   1.427 +
   1.428 +NS_IMETHODIMP
   1.429 +nsLoadGroup::SetLoadFlags(uint32_t aLoadFlags)
   1.430 +{
   1.431 +    mLoadFlags = aLoadFlags;
   1.432 +    return NS_OK;
   1.433 +}
   1.434 +
   1.435 +NS_IMETHODIMP
   1.436 +nsLoadGroup::GetLoadGroup(nsILoadGroup **loadGroup)
   1.437 +{
   1.438 +    *loadGroup = mLoadGroup;
   1.439 +    NS_IF_ADDREF(*loadGroup);
   1.440 +    return NS_OK;
   1.441 +}
   1.442 +
   1.443 +NS_IMETHODIMP
   1.444 +nsLoadGroup::SetLoadGroup(nsILoadGroup *loadGroup)
   1.445 +{
   1.446 +    mLoadGroup = loadGroup;
   1.447 +    return NS_OK;
   1.448 +}
   1.449 +
   1.450 +////////////////////////////////////////////////////////////////////////////////
   1.451 +// nsILoadGroup methods:
   1.452 +
   1.453 +NS_IMETHODIMP
   1.454 +nsLoadGroup::GetDefaultLoadRequest(nsIRequest * *aRequest)
   1.455 +{
   1.456 +    *aRequest = mDefaultLoadRequest;
   1.457 +    NS_IF_ADDREF(*aRequest);
   1.458 +    return NS_OK;
   1.459 +}
   1.460 +
   1.461 +NS_IMETHODIMP
   1.462 +nsLoadGroup::SetDefaultLoadRequest(nsIRequest *aRequest)
   1.463 +{
   1.464 +    mDefaultLoadRequest = aRequest;
   1.465 +    // Inherit the group load flags from the default load request
   1.466 +    if (mDefaultLoadRequest) {
   1.467 +        mDefaultLoadRequest->GetLoadFlags(&mLoadFlags);
   1.468 +        //
   1.469 +        // Mask off any bits that are not part of the nsIRequest flags.
   1.470 +        // in particular, nsIChannel::LOAD_DOCUMENT_URI...
   1.471 +        //
   1.472 +        mLoadFlags &= nsIRequest::LOAD_REQUESTMASK;
   1.473 +
   1.474 +        nsCOMPtr<nsITimedChannel> timedChannel = do_QueryInterface(aRequest);
   1.475 +        mDefaultLoadIsTimed = timedChannel != nullptr;
   1.476 +        if (mDefaultLoadIsTimed) {
   1.477 +            timedChannel->GetChannelCreation(&mDefaultRequestCreationTime);
   1.478 +            timedChannel->SetTimingEnabled(true);
   1.479 +        }
   1.480 +    }
   1.481 +    // Else, do not change the group's load flags (see bug 95981)
   1.482 +    return NS_OK;
   1.483 +}
   1.484 +
   1.485 +NS_IMETHODIMP
   1.486 +nsLoadGroup::AddRequest(nsIRequest *request, nsISupports* ctxt)
   1.487 +{
   1.488 +    nsresult rv;
   1.489 +
   1.490 +#if defined(PR_LOGGING)
   1.491 +    {
   1.492 +        nsAutoCString nameStr;
   1.493 +        request->GetName(nameStr);
   1.494 +        LOG(("LOADGROUP [%x]: Adding request %x %s (count=%d).\n",
   1.495 +             this, request, nameStr.get(), mRequests.entryCount));
   1.496 +    }
   1.497 +#endif /* PR_LOGGING */
   1.498 +
   1.499 +#ifdef DEBUG
   1.500 +    {
   1.501 +      RequestMapEntry *entry =
   1.502 +          static_cast<RequestMapEntry *>
   1.503 +                     (PL_DHashTableOperate(&mRequests, request,
   1.504 +                                          PL_DHASH_LOOKUP));
   1.505 +
   1.506 +      NS_ASSERTION(PL_DHASH_ENTRY_IS_FREE(entry),
   1.507 +                   "Entry added to loadgroup twice, don't do that");
   1.508 +    }
   1.509 +#endif
   1.510 +
   1.511 +    //
   1.512 +    // Do not add the channel, if the loadgroup is being canceled...
   1.513 +    //
   1.514 +    if (mIsCanceling) {
   1.515 +
   1.516 +#if defined(PR_LOGGING)
   1.517 +        LOG(("LOADGROUP [%x]: AddChannel() ABORTED because LoadGroup is"
   1.518 +             " being canceled!!\n", this));
   1.519 +#endif /* PR_LOGGING */
   1.520 +
   1.521 +        return NS_BINDING_ABORTED;
   1.522 +    }
   1.523 +
   1.524 +    nsLoadFlags flags;
   1.525 +    // if the request is the default load request or if the default
   1.526 +    // load request is null, then the load group should inherit its
   1.527 +    // load flags from the request.
   1.528 +    if (mDefaultLoadRequest == request || !mDefaultLoadRequest)
   1.529 +        rv = request->GetLoadFlags(&flags);
   1.530 +    else
   1.531 +        rv = MergeLoadFlags(request, flags);
   1.532 +    if (NS_FAILED(rv)) return rv;
   1.533 +    
   1.534 +    //
   1.535 +    // Add the request to the list of active requests...
   1.536 +    //
   1.537 +
   1.538 +    RequestMapEntry *entry =
   1.539 +        static_cast<RequestMapEntry *>
   1.540 +                   (PL_DHashTableOperate(&mRequests, request,
   1.541 +                                        PL_DHASH_ADD));
   1.542 +
   1.543 +    if (!entry) {
   1.544 +        return NS_ERROR_OUT_OF_MEMORY;
   1.545 +    }
   1.546 +
   1.547 +    if (mPriority != 0)
   1.548 +        RescheduleRequest(request, mPriority);
   1.549 +
   1.550 +    nsCOMPtr<nsITimedChannel> timedChannel = do_QueryInterface(request);
   1.551 +    if (timedChannel)
   1.552 +        timedChannel->SetTimingEnabled(true);
   1.553 +
   1.554 +    if (!(flags & nsIRequest::LOAD_BACKGROUND)) {
   1.555 +        // Update the count of foreground URIs..
   1.556 +        mForegroundCount += 1;
   1.557 +
   1.558 +        //
   1.559 +        // Fire the OnStartRequest notification out to the observer...
   1.560 +        //
   1.561 +        // If the notification fails then DO NOT add the request to
   1.562 +        // the load group.
   1.563 +        //
   1.564 +        nsCOMPtr<nsIRequestObserver> observer = do_QueryReferent(mObserver);
   1.565 +        if (observer) {
   1.566 +            LOG(("LOADGROUP [%x]: Firing OnStartRequest for request %x."
   1.567 +                 "(foreground count=%d).\n", this, request, mForegroundCount));
   1.568 +
   1.569 +            rv = observer->OnStartRequest(request, ctxt);
   1.570 +            if (NS_FAILED(rv)) {
   1.571 +                LOG(("LOADGROUP [%x]: OnStartRequest for request %x FAILED.\n",
   1.572 +                    this, request));
   1.573 +                //
   1.574 +                // The URI load has been canceled by the observer.  Clean up
   1.575 +                // the damage...
   1.576 +                //
   1.577 +
   1.578 +                PL_DHashTableOperate(&mRequests, request, PL_DHASH_REMOVE);
   1.579 +
   1.580 +                rv = NS_OK;
   1.581 +
   1.582 +                mForegroundCount -= 1;
   1.583 +            }
   1.584 +        }
   1.585 +
   1.586 +        // Ensure that we're part of our loadgroup while pending
   1.587 +        if (mForegroundCount == 1 && mLoadGroup) {
   1.588 +            mLoadGroup->AddRequest(this, nullptr);
   1.589 +        }
   1.590 +
   1.591 +    }
   1.592 +
   1.593 +    return rv;
   1.594 +}
   1.595 +
   1.596 +NS_IMETHODIMP
   1.597 +nsLoadGroup::RemoveRequest(nsIRequest *request, nsISupports* ctxt,
   1.598 +                           nsresult aStatus)
   1.599 +{
   1.600 +    NS_ENSURE_ARG_POINTER(request);
   1.601 +    nsresult rv;
   1.602 +
   1.603 +#if defined(PR_LOGGING)
   1.604 +    {
   1.605 +        nsAutoCString nameStr;
   1.606 +        request->GetName(nameStr);
   1.607 +        LOG(("LOADGROUP [%x]: Removing request %x %s status %x (count=%d).\n",
   1.608 +            this, request, nameStr.get(), aStatus, mRequests.entryCount-1));
   1.609 +    }
   1.610 +#endif
   1.611 +
   1.612 +    // Make sure we have a owning reference to the request we're about
   1.613 +    // to remove.
   1.614 +
   1.615 +    nsCOMPtr<nsIRequest> kungFuDeathGrip(request);
   1.616 +
   1.617 +    //
   1.618 +    // Remove the request from the group.  If this fails, it means that
   1.619 +    // the request was *not* in the group so do not update the foreground
   1.620 +    // count or it will get messed up...
   1.621 +    //
   1.622 +    RequestMapEntry *entry =
   1.623 +        static_cast<RequestMapEntry *>
   1.624 +                   (PL_DHashTableOperate(&mRequests, request,
   1.625 +                                        PL_DHASH_LOOKUP));
   1.626 +
   1.627 +    if (PL_DHASH_ENTRY_IS_FREE(entry)) {
   1.628 +        LOG(("LOADGROUP [%x]: Unable to remove request %x. Not in group!\n",
   1.629 +            this, request));
   1.630 +
   1.631 +        return NS_ERROR_FAILURE;
   1.632 +    }
   1.633 +
   1.634 +    PL_DHashTableRawRemove(&mRequests, entry);
   1.635 +
   1.636 +    // Collect telemetry stats only when default request is a timed channel.
   1.637 +    // Don't include failed requests in the timing statistics.
   1.638 +    if (mDefaultLoadIsTimed && NS_SUCCEEDED(aStatus)) {
   1.639 +        nsCOMPtr<nsITimedChannel> timedChannel = do_QueryInterface(request);
   1.640 +        if (timedChannel) {
   1.641 +            // Figure out if this request was served from the cache
   1.642 +            ++mTimedRequests;
   1.643 +            TimeStamp timeStamp;
   1.644 +            rv = timedChannel->GetCacheReadStart(&timeStamp);
   1.645 +            if (NS_SUCCEEDED(rv) && !timeStamp.IsNull()) {
   1.646 +                ++mCachedRequests;
   1.647 +            }
   1.648 +            else {
   1.649 +                mTimedNonCachedRequestsUntilOnEndPageLoad++;
   1.650 +            }
   1.651 +
   1.652 +            rv = timedChannel->GetAsyncOpen(&timeStamp);
   1.653 +            if (NS_SUCCEEDED(rv) && !timeStamp.IsNull()) {
   1.654 +                Telemetry::AccumulateTimeDelta(
   1.655 +                    Telemetry::HTTP_SUBITEM_OPEN_LATENCY_TIME,
   1.656 +                    mDefaultRequestCreationTime, timeStamp);
   1.657 +            }
   1.658 +
   1.659 +            rv = timedChannel->GetResponseStart(&timeStamp);
   1.660 +            if (NS_SUCCEEDED(rv) && !timeStamp.IsNull()) {
   1.661 +                Telemetry::AccumulateTimeDelta(
   1.662 +                    Telemetry::HTTP_SUBITEM_FIRST_BYTE_LATENCY_TIME,
   1.663 +                    mDefaultRequestCreationTime, timeStamp);
   1.664 +            }
   1.665 +
   1.666 +            TelemetryReportChannel(timedChannel, false);
   1.667 +        }
   1.668 +    }
   1.669 +
   1.670 +    if (mRequests.entryCount == 0) {
   1.671 +        TelemetryReport();
   1.672 +    }
   1.673 +
   1.674 +    // Undo any group priority delta...
   1.675 +    if (mPriority != 0)
   1.676 +        RescheduleRequest(request, -mPriority);
   1.677 +
   1.678 +    nsLoadFlags flags;
   1.679 +    rv = request->GetLoadFlags(&flags);
   1.680 +    if (NS_FAILED(rv)) return rv;
   1.681 +
   1.682 +    if (!(flags & nsIRequest::LOAD_BACKGROUND)) {
   1.683 +        NS_ASSERTION(mForegroundCount > 0, "ForegroundCount messed up");
   1.684 +        mForegroundCount -= 1;
   1.685 +
   1.686 +        // Fire the OnStopRequest out to the observer...
   1.687 +        nsCOMPtr<nsIRequestObserver> observer = do_QueryReferent(mObserver);
   1.688 +        if (observer) {
   1.689 +            LOG(("LOADGROUP [%x]: Firing OnStopRequest for request %x."
   1.690 +                 "(foreground count=%d).\n", this, request, mForegroundCount));
   1.691 +
   1.692 +            rv = observer->OnStopRequest(request, ctxt, aStatus);
   1.693 +
   1.694 +#if defined(PR_LOGGING)
   1.695 +            if (NS_FAILED(rv)) {
   1.696 +                LOG(("LOADGROUP [%x]: OnStopRequest for request %x FAILED.\n",
   1.697 +                    this, request));
   1.698 +            }
   1.699 +#endif
   1.700 +        }
   1.701 +
   1.702 +        // If that was the last request -> remove ourselves from loadgroup
   1.703 +        if (mForegroundCount == 0 && mLoadGroup) {
   1.704 +            mLoadGroup->RemoveRequest(this, nullptr, aStatus);
   1.705 +        }
   1.706 +    }
   1.707 +
   1.708 +    return rv;
   1.709 +}
   1.710 +
   1.711 +// PLDHashTable enumeration callback that appends all items in the
   1.712 +// hash to an nsCOMArray
   1.713 +static PLDHashOperator
   1.714 +AppendRequestsToCOMArray(PLDHashTable *table, PLDHashEntryHdr *hdr,
   1.715 +                         uint32_t number, void *arg)
   1.716 +{
   1.717 +    RequestMapEntry *e = static_cast<RequestMapEntry *>(hdr);
   1.718 +    static_cast<nsCOMArray<nsIRequest>*>(arg)->AppendObject(e->mKey);
   1.719 +    return PL_DHASH_NEXT;
   1.720 +}
   1.721 +
   1.722 +NS_IMETHODIMP
   1.723 +nsLoadGroup::GetRequests(nsISimpleEnumerator * *aRequests)
   1.724 +{
   1.725 +    nsCOMArray<nsIRequest> requests;
   1.726 +    requests.SetCapacity(mRequests.entryCount);
   1.727 +
   1.728 +    PL_DHashTableEnumerate(&mRequests, AppendRequestsToCOMArray, &requests);
   1.729 +
   1.730 +    return NS_NewArrayEnumerator(aRequests, requests);
   1.731 +}
   1.732 +
   1.733 +NS_IMETHODIMP
   1.734 +nsLoadGroup::SetGroupObserver(nsIRequestObserver* aObserver)
   1.735 +{
   1.736 +    mObserver = do_GetWeakReference(aObserver);
   1.737 +    return NS_OK;
   1.738 +}
   1.739 +
   1.740 +NS_IMETHODIMP
   1.741 +nsLoadGroup::GetGroupObserver(nsIRequestObserver* *aResult)
   1.742 +{
   1.743 +    nsCOMPtr<nsIRequestObserver> observer = do_QueryReferent(mObserver);
   1.744 +    *aResult = observer;
   1.745 +    NS_IF_ADDREF(*aResult);
   1.746 +    return NS_OK;
   1.747 +}
   1.748 +
   1.749 +NS_IMETHODIMP
   1.750 +nsLoadGroup::GetActiveCount(uint32_t* aResult)
   1.751 +{
   1.752 +    *aResult = mForegroundCount;
   1.753 +    return NS_OK;
   1.754 +}
   1.755 +
   1.756 +NS_IMETHODIMP
   1.757 +nsLoadGroup::GetNotificationCallbacks(nsIInterfaceRequestor **aCallbacks)
   1.758 +{
   1.759 +    NS_ENSURE_ARG_POINTER(aCallbacks);
   1.760 +    *aCallbacks = mCallbacks;
   1.761 +    NS_IF_ADDREF(*aCallbacks);
   1.762 +    return NS_OK;
   1.763 +}
   1.764 +
   1.765 +NS_IMETHODIMP
   1.766 +nsLoadGroup::SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks)
   1.767 +{
   1.768 +    mCallbacks = aCallbacks;
   1.769 +    return NS_OK;
   1.770 +}
   1.771 +
   1.772 +NS_IMETHODIMP
   1.773 +nsLoadGroup::GetConnectionInfo(nsILoadGroupConnectionInfo **aCI)
   1.774 +{
   1.775 +    NS_ENSURE_ARG_POINTER(aCI);
   1.776 +    *aCI = mConnectionInfo;
   1.777 +    NS_IF_ADDREF(*aCI);
   1.778 +    return NS_OK;
   1.779 +}
   1.780 +
   1.781 +////////////////////////////////////////////////////////////////////////////////
   1.782 +// nsILoadGroupChild methods:
   1.783 +
   1.784 +/* attribute nsILoadGroup parentLoadGroup; */
   1.785 +NS_IMETHODIMP
   1.786 +nsLoadGroup::GetParentLoadGroup(nsILoadGroup * *aParentLoadGroup)
   1.787 +{
   1.788 +    *aParentLoadGroup = nullptr;
   1.789 +    nsCOMPtr<nsILoadGroup> parent = do_QueryReferent(mParentLoadGroup);
   1.790 +    if (!parent)
   1.791 +        return NS_OK;
   1.792 +    parent.forget(aParentLoadGroup);
   1.793 +    return NS_OK;
   1.794 +}
   1.795 +
   1.796 +NS_IMETHODIMP
   1.797 +nsLoadGroup::SetParentLoadGroup(nsILoadGroup *aParentLoadGroup)
   1.798 +{
   1.799 +    mParentLoadGroup = do_GetWeakReference(aParentLoadGroup);
   1.800 +    return NS_OK;
   1.801 +}
   1.802 +
   1.803 +/* readonly attribute nsILoadGroup childLoadGroup; */
   1.804 +NS_IMETHODIMP
   1.805 +nsLoadGroup::GetChildLoadGroup(nsILoadGroup * *aChildLoadGroup)
   1.806 +{
   1.807 +    NS_ADDREF(*aChildLoadGroup = this);
   1.808 +    return NS_OK;
   1.809 +}
   1.810 +
   1.811 +/* readonly attribute nsILoadGroup rootLoadGroup; */
   1.812 +NS_IMETHODIMP
   1.813 +nsLoadGroup::GetRootLoadGroup(nsILoadGroup * *aRootLoadGroup)
   1.814 +{
   1.815 +    // first recursively try the root load group of our parent
   1.816 +    nsCOMPtr<nsILoadGroupChild> ancestor = do_QueryReferent(mParentLoadGroup);
   1.817 +    if (ancestor)
   1.818 +        return ancestor->GetRootLoadGroup(aRootLoadGroup);
   1.819 +
   1.820 +    // next recursively try the root load group of our own load grop
   1.821 +    ancestor = do_QueryInterface(mLoadGroup);
   1.822 +    if (ancestor)
   1.823 +        return ancestor->GetRootLoadGroup(aRootLoadGroup);
   1.824 +
   1.825 +    // finally just return this
   1.826 +    NS_ADDREF(*aRootLoadGroup = this);
   1.827 +    return NS_OK;
   1.828 +}
   1.829 +
   1.830 +////////////////////////////////////////////////////////////////////////////////
   1.831 +// nsPILoadGroupInternal methods:
   1.832 +
   1.833 +NS_IMETHODIMP
   1.834 +nsLoadGroup::OnEndPageLoad(nsIChannel *aDefaultChannel)
   1.835 +{
   1.836 +    // for the moment, nothing to do here.
   1.837 +    return NS_OK;
   1.838 +}
   1.839 +
   1.840 +////////////////////////////////////////////////////////////////////////////////
   1.841 +// nsISupportsPriority methods:
   1.842 +
   1.843 +NS_IMETHODIMP
   1.844 +nsLoadGroup::GetPriority(int32_t *aValue)
   1.845 +{
   1.846 +    *aValue = mPriority;
   1.847 +    return NS_OK;
   1.848 +}
   1.849 +
   1.850 +NS_IMETHODIMP
   1.851 +nsLoadGroup::SetPriority(int32_t aValue)
   1.852 +{
   1.853 +    return AdjustPriority(aValue - mPriority);
   1.854 +}
   1.855 +
   1.856 +NS_IMETHODIMP
   1.857 +nsLoadGroup::AdjustPriority(int32_t aDelta)
   1.858 +{
   1.859 +    // Update the priority for each request that supports nsISupportsPriority
   1.860 +    if (aDelta != 0) {
   1.861 +        mPriority += aDelta;
   1.862 +        PL_DHashTableEnumerate(&mRequests, RescheduleRequests, &aDelta);
   1.863 +    }
   1.864 +    return NS_OK;
   1.865 +}
   1.866 +
   1.867 +NS_IMETHODIMP
   1.868 +nsLoadGroup::GetDefaultLoadFlags(uint32_t *aFlags)
   1.869 +{
   1.870 +    *aFlags = mDefaultLoadFlags;
   1.871 +    return NS_OK;
   1.872 +}
   1.873 +
   1.874 +NS_IMETHODIMP
   1.875 +nsLoadGroup::SetDefaultLoadFlags(uint32_t aFlags)
   1.876 +{
   1.877 +    mDefaultLoadFlags = aFlags;
   1.878 +    return NS_OK;
   1.879 +}
   1.880 +
   1.881 +
   1.882 +////////////////////////////////////////////////////////////////////////////////
   1.883 +
   1.884 +void 
   1.885 +nsLoadGroup::TelemetryReport()
   1.886 +{
   1.887 +    if (mDefaultLoadIsTimed) {
   1.888 +        Telemetry::Accumulate(Telemetry::HTTP_REQUEST_PER_PAGE, mTimedRequests);
   1.889 +        if (mTimedRequests) {
   1.890 +            Telemetry::Accumulate(Telemetry::HTTP_REQUEST_PER_PAGE_FROM_CACHE,
   1.891 +                                  mCachedRequests * 100 / mTimedRequests);
   1.892 +        }
   1.893 +
   1.894 +        nsCOMPtr<nsITimedChannel> timedChannel =
   1.895 +            do_QueryInterface(mDefaultLoadRequest);
   1.896 +        if (timedChannel)
   1.897 +            TelemetryReportChannel(timedChannel, true);
   1.898 +    }
   1.899 +
   1.900 +    mTimedRequests = 0;
   1.901 +    mCachedRequests = 0;
   1.902 +    mDefaultLoadIsTimed = false;
   1.903 +}
   1.904 +
   1.905 +void
   1.906 +nsLoadGroup::TelemetryReportChannel(nsITimedChannel *aTimedChannel,
   1.907 +                                    bool aDefaultRequest)
   1.908 +{
   1.909 +    nsresult rv;
   1.910 +    bool timingEnabled;
   1.911 +    rv = aTimedChannel->GetTimingEnabled(&timingEnabled);
   1.912 +    if (NS_FAILED(rv) || !timingEnabled)
   1.913 +        return;
   1.914 +
   1.915 +    TimeStamp asyncOpen;
   1.916 +    rv = aTimedChannel->GetAsyncOpen(&asyncOpen);
   1.917 +    // We do not check !asyncOpen.IsNull() bellow, prevent ASSERTIONs this way
   1.918 +    if (NS_FAILED(rv) || asyncOpen.IsNull())
   1.919 +        return;
   1.920 +
   1.921 +    TimeStamp cacheReadStart;
   1.922 +    rv = aTimedChannel->GetCacheReadStart(&cacheReadStart);
   1.923 +    if (NS_FAILED(rv))
   1.924 +        return;
   1.925 +
   1.926 +    TimeStamp cacheReadEnd;
   1.927 +    rv = aTimedChannel->GetCacheReadEnd(&cacheReadEnd);
   1.928 +    if (NS_FAILED(rv))
   1.929 +        return;
   1.930 +
   1.931 +    TimeStamp domainLookupStart;
   1.932 +    rv = aTimedChannel->GetDomainLookupStart(&domainLookupStart);
   1.933 +    if (NS_FAILED(rv))
   1.934 +        return;
   1.935 +
   1.936 +    TimeStamp domainLookupEnd;
   1.937 +    rv = aTimedChannel->GetDomainLookupEnd(&domainLookupEnd);
   1.938 +    if (NS_FAILED(rv))
   1.939 +        return;
   1.940 +
   1.941 +    TimeStamp connectStart;
   1.942 +    rv = aTimedChannel->GetConnectStart(&connectStart);
   1.943 +    if (NS_FAILED(rv))
   1.944 +        return;
   1.945 +
   1.946 +    TimeStamp connectEnd;
   1.947 +    rv = aTimedChannel->GetConnectEnd(&connectEnd);
   1.948 +    if (NS_FAILED(rv))
   1.949 +        return;
   1.950 +
   1.951 +    TimeStamp requestStart;
   1.952 +    rv = aTimedChannel->GetRequestStart(&requestStart);
   1.953 +    if (NS_FAILED(rv))
   1.954 +        return;
   1.955 +
   1.956 +    TimeStamp responseStart;
   1.957 +    rv = aTimedChannel->GetResponseStart(&responseStart);
   1.958 +    if (NS_FAILED(rv))
   1.959 +        return;
   1.960 +
   1.961 +    TimeStamp responseEnd;
   1.962 +    rv = aTimedChannel->GetResponseEnd(&responseEnd);
   1.963 +    if (NS_FAILED(rv))
   1.964 +        return;
   1.965 +
   1.966 +#define HTTP_REQUEST_HISTOGRAMS(prefix)                                        \
   1.967 +    if (!domainLookupStart.IsNull()) {                                         \
   1.968 +        Telemetry::AccumulateTimeDelta(                                        \
   1.969 +            Telemetry::HTTP_##prefix##_DNS_ISSUE_TIME,                         \
   1.970 +            asyncOpen, domainLookupStart);                                     \
   1.971 +    }                                                                          \
   1.972 +                                                                               \
   1.973 +    if (!domainLookupStart.IsNull() && !domainLookupEnd.IsNull()) {            \
   1.974 +        Telemetry::AccumulateTimeDelta(                                        \
   1.975 +            Telemetry::HTTP_##prefix##_DNS_LOOKUP_TIME,                        \
   1.976 +            domainLookupStart, domainLookupEnd);                               \
   1.977 +    }                                                                          \
   1.978 +                                                                               \
   1.979 +    if (!connectStart.IsNull() && !connectEnd.IsNull()) {                      \
   1.980 +        Telemetry::AccumulateTimeDelta(                                        \
   1.981 +            Telemetry::HTTP_##prefix##_TCP_CONNECTION,                         \
   1.982 +            connectStart, connectEnd);                                         \
   1.983 +    }                                                                          \
   1.984 +                                                                               \
   1.985 +                                                                               \
   1.986 +    if (!requestStart.IsNull() && !responseEnd.IsNull()) {                     \
   1.987 +        Telemetry::AccumulateTimeDelta(                                        \
   1.988 +            Telemetry::HTTP_##prefix##_OPEN_TO_FIRST_SENT,                     \
   1.989 +            asyncOpen, requestStart);                                          \
   1.990 +                                                                               \
   1.991 +        Telemetry::AccumulateTimeDelta(                                        \
   1.992 +            Telemetry::HTTP_##prefix##_FIRST_SENT_TO_LAST_RECEIVED,            \
   1.993 +            requestStart, responseEnd);                                        \
   1.994 +                                                                               \
   1.995 +        if (cacheReadStart.IsNull() && !responseStart.IsNull()) {              \
   1.996 +            Telemetry::AccumulateTimeDelta(                                    \
   1.997 +                Telemetry::HTTP_##prefix##_OPEN_TO_FIRST_RECEIVED,             \
   1.998 +                asyncOpen, responseStart);                                     \
   1.999 +        }                                                                      \
  1.1000 +    }                                                                          \
  1.1001 +                                                                               \
  1.1002 +    if (!cacheReadStart.IsNull() && !cacheReadEnd.IsNull()) {                  \
  1.1003 +        if (!CacheObserver::UseNewCache()) {                                   \
  1.1004 +            Telemetry::AccumulateTimeDelta(                                    \
  1.1005 +                Telemetry::HTTP_##prefix##_OPEN_TO_FIRST_FROM_CACHE,           \
  1.1006 +                asyncOpen, cacheReadStart);                                    \
  1.1007 +        } else {                                                               \
  1.1008 +            Telemetry::AccumulateTimeDelta(                                    \
  1.1009 +                Telemetry::HTTP_##prefix##_OPEN_TO_FIRST_FROM_CACHE_V2,        \
  1.1010 +                asyncOpen, cacheReadStart);                                    \
  1.1011 +        }                                                                      \
  1.1012 +                                                                               \
  1.1013 +        if (!CacheObserver::UseNewCache()) {                                   \
  1.1014 +            Telemetry::AccumulateTimeDelta(                                    \
  1.1015 +                Telemetry::HTTP_##prefix##_CACHE_READ_TIME,                    \
  1.1016 +                cacheReadStart, cacheReadEnd);                                 \
  1.1017 +        } else {                                                               \
  1.1018 +            Telemetry::AccumulateTimeDelta(                                    \
  1.1019 +                Telemetry::HTTP_##prefix##_CACHE_READ_TIME_V2,                 \
  1.1020 +                cacheReadStart, cacheReadEnd);                                 \
  1.1021 +        }                                                                      \
  1.1022 +                                                                               \
  1.1023 +        if (!requestStart.IsNull() && !responseEnd.IsNull()) {                 \
  1.1024 +            Telemetry::AccumulateTimeDelta(                                    \
  1.1025 +                Telemetry::HTTP_##prefix##_REVALIDATION,                       \
  1.1026 +                requestStart, responseEnd);                                    \
  1.1027 +        }                                                                      \
  1.1028 +    }                                                                          \
  1.1029 +                                                                               \
  1.1030 +    if (!cacheReadEnd.IsNull()) {                                              \
  1.1031 +        Telemetry::AccumulateTimeDelta(                                        \
  1.1032 +            Telemetry::HTTP_##prefix##_COMPLETE_LOAD,                          \
  1.1033 +            asyncOpen, cacheReadEnd);                                          \
  1.1034 +                                                                               \
  1.1035 +        if (!CacheObserver::UseNewCache()) {                                   \
  1.1036 +            Telemetry::AccumulateTimeDelta(                                    \
  1.1037 +                Telemetry::HTTP_##prefix##_COMPLETE_LOAD_CACHED,               \
  1.1038 +                asyncOpen, cacheReadEnd);                                      \
  1.1039 +        } else {                                                               \
  1.1040 +            Telemetry::AccumulateTimeDelta(                                    \
  1.1041 +                Telemetry::HTTP_##prefix##_COMPLETE_LOAD_CACHED_V2,            \
  1.1042 +                asyncOpen, cacheReadEnd);                                      \
  1.1043 +        }                                                                      \
  1.1044 +    }                                                                          \
  1.1045 +    else if (!responseEnd.IsNull()) {                                          \
  1.1046 +        if (!CacheObserver::UseNewCache()) {                                   \
  1.1047 +            Telemetry::AccumulateTimeDelta(                                    \
  1.1048 +                Telemetry::HTTP_##prefix##_COMPLETE_LOAD,                      \
  1.1049 +                asyncOpen, responseEnd);                                       \
  1.1050 +            Telemetry::AccumulateTimeDelta(                                    \
  1.1051 +                Telemetry::HTTP_##prefix##_COMPLETE_LOAD_NET,                  \
  1.1052 +                asyncOpen, responseEnd);                                       \
  1.1053 +        } else {                                                               \
  1.1054 +            Telemetry::AccumulateTimeDelta(                                    \
  1.1055 +                Telemetry::HTTP_##prefix##_COMPLETE_LOAD_V2,                   \
  1.1056 +                asyncOpen, responseEnd);                                       \
  1.1057 +            Telemetry::AccumulateTimeDelta(                                    \
  1.1058 +                Telemetry::HTTP_##prefix##_COMPLETE_LOAD_NET_V2,               \
  1.1059 +                asyncOpen, responseEnd);                                       \
  1.1060 +        }                                                                      \
  1.1061 +    }
  1.1062 +
  1.1063 +    if (aDefaultRequest) {
  1.1064 +        HTTP_REQUEST_HISTOGRAMS(PAGE)
  1.1065 +    } else {
  1.1066 +        HTTP_REQUEST_HISTOGRAMS(SUB)
  1.1067 +    }
  1.1068 +#undef HTTP_REQUEST_HISTOGRAMS
  1.1069 +}
  1.1070 +
  1.1071 +nsresult nsLoadGroup::MergeLoadFlags(nsIRequest *aRequest, nsLoadFlags& outFlags)
  1.1072 +{
  1.1073 +    nsresult rv;
  1.1074 +    nsLoadFlags flags, oldFlags;
  1.1075 +
  1.1076 +    rv = aRequest->GetLoadFlags(&flags);
  1.1077 +    if (NS_FAILED(rv)) 
  1.1078 +        return rv;
  1.1079 +
  1.1080 +    oldFlags = flags;
  1.1081 +
  1.1082 +    // Inherit the following bits...
  1.1083 +    flags |= (mLoadFlags & (LOAD_BACKGROUND |
  1.1084 +                            LOAD_BYPASS_CACHE |
  1.1085 +                            LOAD_FROM_CACHE |
  1.1086 +                            VALIDATE_ALWAYS |
  1.1087 +                            VALIDATE_ONCE_PER_SESSION |
  1.1088 +                            VALIDATE_NEVER));
  1.1089 +
  1.1090 +    // ... and force the default flags.
  1.1091 +    flags |= mDefaultLoadFlags;
  1.1092 +
  1.1093 +    if (flags != oldFlags)
  1.1094 +        rv = aRequest->SetLoadFlags(flags);
  1.1095 +
  1.1096 +    outFlags = flags;
  1.1097 +    return rv;
  1.1098 +}
  1.1099 +
  1.1100 +// nsLoadGroupConnectionInfo
  1.1101 +
  1.1102 +class nsLoadGroupConnectionInfo MOZ_FINAL : public nsILoadGroupConnectionInfo
  1.1103 +{
  1.1104 +public:
  1.1105 +    NS_DECL_THREADSAFE_ISUPPORTS
  1.1106 +    NS_DECL_NSILOADGROUPCONNECTIONINFO
  1.1107 +
  1.1108 +    nsLoadGroupConnectionInfo();
  1.1109 +private:
  1.1110 +    Atomic<uint32_t>       mBlockingTransactionCount;
  1.1111 +    nsAutoPtr<mozilla::net::SpdyPushCache> mSpdyCache;
  1.1112 +};
  1.1113 +
  1.1114 +NS_IMPL_ISUPPORTS(nsLoadGroupConnectionInfo, nsILoadGroupConnectionInfo)
  1.1115 +
  1.1116 +nsLoadGroupConnectionInfo::nsLoadGroupConnectionInfo()
  1.1117 +    : mBlockingTransactionCount(0)
  1.1118 +{
  1.1119 +}
  1.1120 +
  1.1121 +NS_IMETHODIMP
  1.1122 +nsLoadGroupConnectionInfo::GetBlockingTransactionCount(uint32_t *aBlockingTransactionCount)
  1.1123 +{
  1.1124 +    NS_ENSURE_ARG_POINTER(aBlockingTransactionCount);
  1.1125 +    *aBlockingTransactionCount = mBlockingTransactionCount;
  1.1126 +    return NS_OK;
  1.1127 +}
  1.1128 +
  1.1129 +NS_IMETHODIMP
  1.1130 +nsLoadGroupConnectionInfo::AddBlockingTransaction()
  1.1131 +{
  1.1132 +    mBlockingTransactionCount++;
  1.1133 +    return NS_OK;
  1.1134 +}
  1.1135 +
  1.1136 +NS_IMETHODIMP
  1.1137 +nsLoadGroupConnectionInfo::RemoveBlockingTransaction(uint32_t *_retval)
  1.1138 +{
  1.1139 +    NS_ENSURE_ARG_POINTER(_retval);
  1.1140 +        mBlockingTransactionCount--;
  1.1141 +        *_retval = mBlockingTransactionCount;
  1.1142 +    return NS_OK;
  1.1143 +}
  1.1144 +
  1.1145 +/* [noscript] attribute SpdyPushCachePtr spdyPushCache; */
  1.1146 +NS_IMETHODIMP
  1.1147 +nsLoadGroupConnectionInfo::GetSpdyPushCache(mozilla::net::SpdyPushCache **aSpdyPushCache)
  1.1148 +{
  1.1149 +    *aSpdyPushCache = mSpdyCache.get();
  1.1150 +    return NS_OK;
  1.1151 +}
  1.1152 +
  1.1153 +NS_IMETHODIMP
  1.1154 +nsLoadGroupConnectionInfo::SetSpdyPushCache(mozilla::net::SpdyPushCache *aSpdyPushCache)
  1.1155 +{
  1.1156 +    mSpdyCache = aSpdyPushCache;
  1.1157 +    return NS_OK;
  1.1158 +}
  1.1159 +
  1.1160 +nsresult nsLoadGroup::Init()
  1.1161 +{
  1.1162 +    static const PLDHashTableOps hash_table_ops =
  1.1163 +    {
  1.1164 +        PL_DHashAllocTable,
  1.1165 +        PL_DHashFreeTable,
  1.1166 +        PL_DHashVoidPtrKeyStub,
  1.1167 +        RequestHashMatchEntry,
  1.1168 +        PL_DHashMoveEntryStub,
  1.1169 +        RequestHashClearEntry,
  1.1170 +        PL_DHashFinalizeStub,
  1.1171 +        RequestHashInitEntry
  1.1172 +    };
  1.1173 +
  1.1174 +    PL_DHashTableInit(&mRequests, &hash_table_ops, nullptr,
  1.1175 +                      sizeof(RequestMapEntry), 16);
  1.1176 +
  1.1177 +    mConnectionInfo = new nsLoadGroupConnectionInfo();
  1.1178 +
  1.1179 +    return NS_OK;
  1.1180 +}
  1.1181 +
  1.1182 +#undef LOG

mercurial