chrome/nsChromeProtocolHandler.cpp
author Andrew Osmond <aosmond@mozilla.com>
Tue, 16 Oct 2018 08:45:26 -0400
changeset 447457 ccfa531dea0301244c99db4ff26d5610382487e2
parent 417734 c10e876269a946c970da95bbd9f8063f3fd5f364
child 448947 6f3709b3878117466168c40affa7bca0b60cf75b
permissions -rw-r--r--
Bug 1504699 - Part 7. Update animated image recycling queue to work well with WebRender. r=tnikkel WebRender takes longer than OMTP to release its hold on the current frame. This is because it is in a separate process and holds onto the surface in between rendering frames, rather than getting a reference for each repaint. This patch makes us less aggressive about taking the most recent surface placed in the recycling queue out to avoid blocking on waiting for the surface to be released. Differential Revision: https://phabricator.services.mozilla.com/D10903

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim:set ts=4 sw=4 sts=4 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/. */

/*

  A protocol handler for ``chrome:''

*/

#include "nsChromeProtocolHandler.h"
#include "nsChromeRegistry.h"
#include "nsCOMPtr.h"
#include "nsContentUtils.h"
#include "nsThreadUtils.h"
#include "nsIChannel.h"
#include "nsIChromeRegistry.h"
#include "nsIFile.h"
#include "nsIFileChannel.h"
#include "nsIIOService.h"
#include "nsILoadGroup.h"
#include "nsIScriptSecurityManager.h"
#include "nsIStandardURL.h"
#include "nsNetUtil.h"
#include "nsNetCID.h"
#include "nsIURL.h"
#include "nsString.h"
#include "nsStandardURL.h"

////////////////////////////////////////////////////////////////////////////////

NS_IMPL_ISUPPORTS(nsChromeProtocolHandler,
                  nsIProtocolHandler,
                  nsISupportsWeakReference)

////////////////////////////////////////////////////////////////////////////////
// nsIProtocolHandler methods:

NS_IMETHODIMP
nsChromeProtocolHandler::GetScheme(nsACString &result)
{
    result.AssignLiteral("chrome");
    return NS_OK;
}

NS_IMETHODIMP
nsChromeProtocolHandler::GetDefaultPort(int32_t *result)
{
    *result = -1;        // no port for chrome: URLs
    return NS_OK;
}

NS_IMETHODIMP
nsChromeProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *_retval)
{
    // don't override anything.
    *_retval = false;
    return NS_OK;
}

NS_IMETHODIMP
nsChromeProtocolHandler::GetProtocolFlags(uint32_t *result)
{
    *result = URI_STD | URI_IS_UI_RESOURCE | URI_IS_LOCAL_RESOURCE;
    return NS_OK;
}

NS_IMETHODIMP
nsChromeProtocolHandler::NewURI(const nsACString &aSpec,
                                const char *aCharset,
                                nsIURI *aBaseURI,
                                nsIURI **result)
{

    // Chrome: URLs (currently) have no additional structure beyond that provided
    // by standard URLs, so there is no "outer" given to CreateInstance
    nsresult rv;
    nsCOMPtr<nsIURI> surl;
    nsCOMPtr<nsIURI> base(aBaseURI);
    rv = NS_MutateURI(new mozilla::net::nsStandardURL::Mutator())
           .Apply(NS_MutatorMethod(&nsIStandardURLMutator::Init,
                                   nsIStandardURL::URLTYPE_STANDARD,
                                   -1, nsCString(aSpec), aCharset,
                                   base, nullptr))
           .Finalize(surl);
    if (NS_FAILED(rv)) {
        return rv;
    }

    // Canonify the "chrome:" URL; e.g., so that we collapse
    // "chrome://navigator/content/" and "chrome://navigator/content"
    // and "chrome://navigator/content/navigator.xul".

    rv = nsChromeRegistry::Canonify(surl);
    if (NS_FAILED(rv))
        return rv;

    surl.forget(result);
    return NS_OK;
}

NS_IMETHODIMP
nsChromeProtocolHandler::NewChannel2(nsIURI* aURI,
                                     nsILoadInfo* aLoadInfo,
                                     nsIChannel** aResult)
{
    nsresult rv;

    NS_ENSURE_ARG_POINTER(aURI);
    NS_ENSURE_ARG_POINTER(aLoadInfo);

    MOZ_ASSERT(aResult, "Null out param");

#ifdef DEBUG
    // Check that the uri we got is already canonified
    nsresult debug_rv;
    nsCOMPtr<nsIURI> debugURL = aURI;
    debug_rv = nsChromeRegistry::Canonify(debugURL);
    if (NS_SUCCEEDED(debug_rv)) {
        bool same;
        debug_rv = aURI->Equals(debugURL, &same);
        if (NS_SUCCEEDED(debug_rv)) {
            NS_ASSERTION(same, "Non-canonified chrome uri passed to nsChromeProtocolHandler::NewChannel!");
        }
    }
#endif

    nsCOMPtr<nsIChannel> result;

    if (!nsChromeRegistry::gChromeRegistry) {
        // We don't actually want this ref, we just want the service to
        // initialize if it hasn't already.
        nsCOMPtr<nsIChromeRegistry> reg =
            mozilla::services::GetChromeRegistryService();
        NS_ENSURE_TRUE(nsChromeRegistry::gChromeRegistry, NS_ERROR_FAILURE);
    }

    nsCOMPtr<nsIURI> resolvedURI;
    rv = nsChromeRegistry::gChromeRegistry->ConvertChromeURL(aURI, getter_AddRefs(resolvedURI));
    if (NS_FAILED(rv)) {
#ifdef DEBUG
        printf("Couldn't convert chrome URL: %s\n",
               aURI->GetSpecOrDefault().get());
#endif
        return rv;
    }

    // We don't want to allow the inner protocol handler modify the result principal URI
    // since we want either |aURI| or anything pre-set by upper layers to prevail.
    nsCOMPtr<nsIURI> savedResultPrincipalURI;
    rv = aLoadInfo->GetResultPrincipalURI(getter_AddRefs(savedResultPrincipalURI));
    NS_ENSURE_SUCCESS(rv, rv);

    rv = NS_NewChannelInternal(getter_AddRefs(result),
                               resolvedURI,
                               aLoadInfo);
    NS_ENSURE_SUCCESS(rv, rv);

#ifdef DEBUG
    nsCOMPtr<nsIFileChannel> fileChan(do_QueryInterface(result));
    if (fileChan) {
        nsCOMPtr<nsIFile> file;
        fileChan->GetFile(getter_AddRefs(file));

        bool exists = false;
        file->Exists(&exists);
        if (!exists) {
            printf("Chrome file doesn't exist: %s\n",
                   file->HumanReadablePath().get());
        }
    }
#endif

    // Make sure that the channel remembers where it was
    // originally loaded from.
    rv = aLoadInfo->SetResultPrincipalURI(savedResultPrincipalURI);
    NS_ENSURE_SUCCESS(rv, rv);
    rv = result->SetOriginalURI(aURI);
    if (NS_FAILED(rv)) return rv;

    // Get a system principal for content files and set the owner
    // property of the result
    nsCOMPtr<nsIURL> url = do_QueryInterface(aURI);
    nsAutoCString path;
    rv = url->GetPathQueryRef(path);
    if (StringBeginsWith(path, NS_LITERAL_CSTRING("/content/"))) {
        result->SetOwner(nsContentUtils::GetSystemPrincipal());
    }

    // XXX Removed dependency-tracking code from here, because we're not
    // tracking them anyways (with fastload we checked only in DEBUG
    // and with startupcache not at all), but this is where we would start
    // if we need to re-add.
    // See bug 531886, bug 533038.
    result->SetContentCharset(NS_LITERAL_CSTRING("UTF-8"));

    *aResult = result;
    NS_ADDREF(*aResult);
    return NS_OK;
}

NS_IMETHODIMP
nsChromeProtocolHandler::NewChannel(nsIURI* aURI,
                                    nsIChannel* *aResult)
{
  return NewChannel2(aURI, nullptr, aResult);
}

////////////////////////////////////////////////////////////////////////////////