# Global Metrics

path: .metrics.cyclomatic.average
old: 3.628205128205128
new: 2.6666666666666665
path: .metrics.cyclomatic.sum
old: 283.0
new: 48.0
path: .metrics.nargs.sum
old: 131.0
new: 33.0
path: .metrics.nargs.average
old: 2.7872340425531914
new: 1.65
path: .metrics.halstead.vocabulary
old: 429.0
new: 214.0
path: .metrics.halstead.level
old: 0.007592190889370932
new: 0.024255932870066867
path: .metrics.halstead.n2
old: 385.0
new: 185.0
path: .metrics.halstead.N2
old: 2305.0
new: 526.0
path: .metrics.halstead.estimated_program_length
old: 3546.870125919213
new: 1534.1870190542172
path: .metrics.halstead.length
old: 5741.0
new: 1215.0
path: .metrics.halstead.time
old: 367366.4441136529
new: 21543.142635710836
path: .metrics.halstead.bugs
old: 11.743387862441043
new: 1.7725552733416847
path: .metrics.halstead.n1
old: 44.0
new: 29.0
path: .metrics.halstead.purity_ratio
old: 0.6178139916250153
new: 1.262705365476722
path: .metrics.halstead.volume
old: 50204.09106108489
new: 9405.882388477394
path: .metrics.halstead.N1
old: 3436.0
new: 689.0
path: .metrics.halstead.difficulty
old: 131.71428571428572
new: 41.22702702702703
path: .metrics.halstead.effort
old: 6612595.994045753
new: 387776.567442795
path: .metrics.nexits.average
old: 2.3404255319148937
new: 1.25
path: .metrics.nexits.sum
old: 110.0
new: 25.0
path: .metrics.cognitive.average
old: 6.0638297872340425
new: 1.6
path: .metrics.cognitive.sum
old: 285.0
new: 32.0
path: .metrics.nom.closures
old: 0.0
new: 4.0
path: .metrics.nom.total
old: 47.0
new: 20.0
path: .metrics.nom.functions
old: 47.0
new: 16.0
path: .metrics.mi.mi_sei
old: -131.92486650131696
new: -19.759432087242445
path: .metrics.mi.mi_original
old: -71.49288192237525
new: 18.003527356008362
path: .metrics.mi.mi_visual_studio
old: 0.0
new: 10.528378570765124
path: .metrics.loc.ploc
old: 1354.0
new: 238.0
path: .metrics.loc.sloc
old: 1766.0
new: 339.0
path: .metrics.loc.cloc
old: 101.0
new: 39.0
path: .metrics.loc.blank
old: 311.0
new: 62.0
path: .metrics.loc.lloc
old: 473.0
new: 98.0

# Spaces Data

## Minimal test - lines (25, 339)

path: .spaces[0].metrics.cyclomatic.sum
old: 1.0
new: 47.0
path: .spaces[0].metrics.cyclomatic.average
old: 1.0
new: 2.764705882352941
path: .spaces[0].metrics.nexits.average
old: 1.0
new: 1.25
path: .spaces[0].metrics.nexits.sum
old: 1.0
new: 25.0
path: .spaces[0].metrics.nom.total
old: 1.0
new: 20.0
path: .spaces[0].metrics.nom.closures
old: 0.0
new: 4.0
path: .spaces[0].metrics.nom.functions
old: 1.0
new: 16.0
path: .spaces[0].metrics.mi.mi_sei
old: 107.29917031068469
new: -19.000811429000716
path: .spaces[0].metrics.mi.mi_original
old: 126.77537335305064
new: 19.558554054793404
path: .spaces[0].metrics.mi.mi_visual_studio
old: 74.13764523570212
new: 11.437750909235907
path: .spaces[0].metrics.loc.cloc
old: 0.0
new: 32.0
path: .spaces[0].metrics.loc.blank
old: 0.0
new: 60.0
path: .spaces[0].metrics.loc.lloc
old: 1.0
new: 98.0
path: .spaces[0].metrics.loc.ploc
old: 4.0
new: 223.0
path: .spaces[0].metrics.loc.sloc
old: 4.0
new: 315.0
path: .spaces[0].metrics.cognitive.sum
old: 0.0
new: 32.0
path: .spaces[0].metrics.cognitive.average
old: 0.0
new: 1.6
path: .spaces[0].metrics.nargs.sum
old: 2.0
new: 33.0
path: .spaces[0].metrics.nargs.average
old: 2.0
new: 1.65
path: .spaces[0].metrics.halstead.bugs
old: 0.013469665311234006
new: 1.807842223793048
path: .spaces[0].metrics.halstead.n2
old: 6.0
new: 170.0
path: .spaces[0].metrics.halstead.N1
old: 10.0
new: 689.0
path: .spaces[0].metrics.halstead.volume
old: 62.907475208398566
new: 9163.949544652378
path: .spaces[0].metrics.halstead.level
old: 0.2448979591836735
new: 0.02294351845603617
path: .spaces[0].metrics.halstead.difficulty
old: 4.083333333333333
new: 43.58529411764706
path: .spaces[0].metrics.halstead.n1
old: 7.0
new: 29.0
path: .spaces[0].metrics.halstead.length
old: 17.0
new: 1200.0
path: .spaces[0].metrics.halstead.time
old: 14.270677246349672
new: 22189.635343497317
path: .spaces[0].metrics.halstead.purity_ratio
old: 2.068309379925304
new: 1.1670649233350907
path: .spaces[0].metrics.halstead.effort
old: 256.8721904342941
new: 399413.4361829518
path: .spaces[0].metrics.halstead.N2
old: 7.0
new: 511.0
path: .spaces[0].metrics.halstead.vocabulary
old: 13.0
new: 199.0
path: .spaces[0].metrics.halstead.estimated_program_length
old: 35.161259458730164
new: 1400.4779080021087

### Code

    namespace mozilla {

    NS_IMPL_ISUPPORTS(FetchPreloader, nsIStreamListener, nsIRequestObserver)

    FetchPreloader::FetchPreloader()
        : FetchPreloader(nsIContentPolicy::TYPE_INTERNAL_FETCH_PRELOAD) {}

    FetchPreloader::FetchPreloader(nsContentPolicyType aContentPolicyType)
        : mContentPolicyType(aContentPolicyType) {}

    nsresult FetchPreloader::OpenChannel(const PreloadHashKey& aKey, nsIURI* aURI,
                                         const CORSMode aCORSMode,
                                         const dom::ReferrerPolicy& aReferrerPolicy,
                                         dom::Document* aDocument) {
      nsresult rv;
      nsCOMPtr channel;

      auto notify = MakeScopeExit([&]() {
        if (NS_FAILED(rv)) {
          // Make sure we notify any  elements when opening fails
          // because of various technical or security reasons.
          NotifyStart(channel);
          // Using the non-channel overload of this method to make it work even
          // before NotifyOpen has been called on this preload.  We are not
          // switching between channels, so it's safe to do so.
          NotifyStop(rv);
        }
      });

      nsCOMPtr loadGroup = aDocument->GetDocumentLoadGroup();
      nsCOMPtr window = aDocument->GetWindow();
      nsCOMPtr prompter;
      if (window) {
        nsIDocShell* docshell = window->GetDocShell();
        prompter = do_QueryInterface(docshell);
      }

      rv = CreateChannel(getter_AddRefs(channel), aURI, aCORSMode, aReferrerPolicy,
                         aDocument, loadGroup, prompter);
      NS_ENSURE_SUCCESS(rv, rv);

      // Doing this now so that we have the channel and tainting set on it properly
      // to notify the proper event (load or error) on the associated preload tags
      // when the CSP check fails.
      rv = CheckContentPolicy(aURI, aDocument);
      if (NS_FAILED(rv)) {
        return rv;
      }

      PrioritizeAsPreload(channel);
      AddLoadBackgroundFlag(channel);

      NotifyOpen(aKey, channel, aDocument, true);

      return mAsyncConsumeResult = rv = channel->AsyncOpen(this);
    }

    nsresult FetchPreloader::CreateChannel(
        nsIChannel** aChannel, nsIURI* aURI, const CORSMode aCORSMode,
        const dom::ReferrerPolicy& aReferrerPolicy, dom::Document* aDocument,
        nsILoadGroup* aLoadGroup, nsIInterfaceRequestor* aCallbacks) {
      nsresult rv;

      nsSecurityFlags securityFlags =
          aCORSMode == CORS_NONE
              ? nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL
              : nsILoadInfo::SEC_REQUIRE_CORS_INHERITS_SEC_CONTEXT;
      if (aCORSMode == CORS_ANONYMOUS) {
        securityFlags |= nsILoadInfo::SEC_COOKIES_SAME_ORIGIN;
      } else if (aCORSMode == CORS_USE_CREDENTIALS) {
        securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
      }

      nsCOMPtr channel;
      rv = NS_NewChannelWithTriggeringPrincipal(
          getter_AddRefs(channel), aURI, aDocument, aDocument->NodePrincipal(),
          securityFlags, nsIContentPolicy::TYPE_FETCH, nullptr, aLoadGroup,
          aCallbacks);
      if (NS_FAILED(rv)) {
        return rv;
      }

      if (nsCOMPtr httpChannel = do_QueryInterface(channel)) {
        nsCOMPtr referrerInfo = new dom::ReferrerInfo(
            aDocument->GetDocumentURIAsReferrer(), aReferrerPolicy);
        rv = httpChannel->SetReferrerInfoWithoutClone(referrerInfo);
        MOZ_ASSERT(NS_SUCCEEDED(rv));
      }

      if (nsCOMPtr timedChannel = do_QueryInterface(channel)) {
        timedChannel->SetInitiatorType(u"link"_ns);
      }

      channel.forget(aChannel);
      return NS_OK;
    }

    nsresult FetchPreloader::CheckContentPolicy(nsIURI* aURI,
                                                dom::Document* aDocument) {
      if (!aDocument) {
        return NS_OK;
      }

      nsCOMPtr secCheckLoadInfo = new net::LoadInfo(
          aDocument->NodePrincipal(), aDocument->NodePrincipal(), aDocument,
          nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK, mContentPolicyType);

      int16_t shouldLoad = nsIContentPolicy::ACCEPT;
      nsresult rv =
          NS_CheckContentLoadPolicy(aURI, secCheckLoadInfo, ""_ns, &shouldLoad,
                                    nsContentUtils::GetContentPolicy());
      if (NS_SUCCEEDED(rv) && NS_CP_ACCEPTED(shouldLoad)) {
        return NS_OK;
      }

      return NS_ERROR_CONTENT_BLOCKED;
    }

    // PreloaderBase

    nsresult FetchPreloader::AsyncConsume(nsIStreamListener* aListener) {
      if (NS_FAILED(mAsyncConsumeResult)) {
        // Already being consumed or failed to open.
        return mAsyncConsumeResult;
      }

      // Prevent duplicate calls.
      mAsyncConsumeResult = NS_ERROR_NOT_AVAILABLE;

      if (!mConsumeListener) {
        // Called before we are getting response from the channel.
        mConsumeListener = aListener;
      } else {
        // Channel already started, push cached calls to this listener.
        // Can't be anything else than the `Cache`, hence a safe static_cast.
        Cache* cache = static_cast(mConsumeListener.get());
        cache->AsyncConsume(aListener);
      }

      return NS_OK;
    }

    // static
    void FetchPreloader::PrioritizeAsPreload(nsIChannel* aChannel) {
      if (nsCOMPtr cos = do_QueryInterface(aChannel)) {
        cos->AddClassFlags(nsIClassOfService::Unblocked);
      }
    }

    void FetchPreloader::PrioritizeAsPreload() { PrioritizeAsPreload(Channel()); }

    // nsIRequestObserver + nsIStreamListener

    NS_IMETHODIMP FetchPreloader::OnStartRequest(nsIRequest* request) {
      NotifyStart(request);

      if (!mConsumeListener) {
        // AsyncConsume not called yet.
        mConsumeListener = new Cache();
      }

      return mConsumeListener->OnStartRequest(request);
    }

    NS_IMETHODIMP FetchPreloader::OnDataAvailable(nsIRequest* request,
                                                  nsIInputStream* input,
                                                  uint64_t offset, uint32_t count) {
      return mConsumeListener->OnDataAvailable(request, input, offset, count);
    }

    NS_IMETHODIMP FetchPreloader::OnStopRequest(nsIRequest* request,
                                                nsresult status) {
      mConsumeListener->OnStopRequest(request, status);

      // We want 404 or other types of server responses to be treated as 'error'.
      if (nsCOMPtr httpChannel = do_QueryInterface(request)) {
        uint32_t responseStatus = 0;
        Unused << httpChannel->GetResponseStatus(&responseStatus);
        if (responseStatus / 100 != 2) {
          status = NS_ERROR_FAILURE;
        }
      }

      // Fetch preloader wants to keep the channel around so that consumers like XHR
      // can access it even after the preload is done.
      nsCOMPtr channel = mChannel;
      NotifyStop(request, status);
      mChannel.swap(channel);
      return NS_OK;
    }

    // FetchPreloader::Cache

    NS_IMPL_ISUPPORTS(FetchPreloader::Cache, nsIStreamListener, nsIRequestObserver)

    NS_IMETHODIMP FetchPreloader::Cache::OnStartRequest(nsIRequest* request) {
      mRequest = request;

      if (mFinalListener) {
        return mFinalListener->OnStartRequest(mRequest);
      }

      mCalls.AppendElement(Call{VariantIndex<0>{}, StartRequest{}});
      return NS_OK;
    }

    NS_IMETHODIMP FetchPreloader::Cache::OnDataAvailable(nsIRequest* request,
                                                         nsIInputStream* input,
                                                         uint64_t offset,
                                                         uint32_t count) {
      if (mFinalListener) {
        return mFinalListener->OnDataAvailable(mRequest, input, offset, count);
      }

      DataAvailable data;
      if (!data.mData.SetLength(count, fallible)) {
        return NS_ERROR_OUT_OF_MEMORY;
      }

      uint32_t read;
      nsresult rv = input->Read(data.mData.BeginWriting(), count, &read);
      if (NS_FAILED(rv)) {
        return rv;
      }

      mCalls.AppendElement(Call{VariantIndex<1>{}, std::move(data)});
      return NS_OK;
    }

    NS_IMETHODIMP FetchPreloader::Cache::OnStopRequest(nsIRequest* request,
                                                       nsresult status) {
      if (mFinalListener) {
        return mFinalListener->OnStopRequest(mRequest, status);
      }

      mCalls.AppendElement(Call{VariantIndex<2>{}, StopRequest{status}});
      return NS_OK;
    }

    void FetchPreloader::Cache::AsyncConsume(nsIStreamListener* aListener) {
      // Must dispatch for two reasons:
      // 1. This is called directly from FetchLoader::AsyncConsume, which must
      // behave the same way as nsIChannel::AsyncOpen.
      // 2. In case there are already stream listener events scheduled on the main
      // thread we preserve the order - those will still end up in Cache.

      // * The `Cache` object is fully main thread only for now, doesn't support
      // retargeting, but it can be improved to allow it.

      nsCOMPtr listener(aListener);
      NS_DispatchToMainThread(NewRunnableMethod>(
          "FetchPreloader::Cache::Consume", this, &FetchPreloader::Cache::Consume,
          listener));
    }

    void FetchPreloader::Cache::Consume(nsCOMPtr aListener) {
      MOZ_ASSERT(!mFinalListener, "Duplicate call");

      mFinalListener = std::move(aListener);

      // Status of the channel read after each call.
      nsresult status = NS_OK;
      nsCOMPtr channel(do_QueryInterface(mRequest));

      RefPtr self(this);
      for (auto& call : mCalls) {
        nsresult rv = call.match(
            [&](const StartRequest& startRequest) mutable {
              return self->mFinalListener->OnStartRequest(self->mRequest);
            },
            [&](const DataAvailable& dataAvailable) mutable {
              if (NS_FAILED(status)) {
                // Channel has been cancelled during this mCalls loop.
                return NS_OK;
              }

              nsCOMPtr input;
              rv = NS_NewCStringInputStream(getter_AddRefs(input),
                                            dataAvailable.mData);
              if (NS_FAILED(rv)) {
                return rv;
              }

              return self->mFinalListener->OnDataAvailable(
                  self->mRequest, input, 0, dataAvailable.mData.Length());
            },
            [&](const StopRequest& stopRequest) {
              // First cancellation overrides mStatus in nsHttpChannel.
              nsresult stopStatus =
                  NS_FAILED(status) ? status : stopRequest.mStatus;
              self->mFinalListener->OnStopRequest(self->mRequest, stopStatus);
              self->mFinalListener = nullptr;
              self->mRequest = nullptr;
              return NS_OK;
            });

        if (!mRequest) {
          // We are done!
          break;
        }

        bool isCancelled = false;
        Unused << channel->GetCanceled(&isCancelled);
        if (isCancelled) {
          mRequest->GetStatus(&status);
        } else if (NS_FAILED(rv)) {
          status = rv;
          mRequest->Cancel(status);
        }
      }

      mCalls.Clear();
    }

    }  // namespace mozilla