mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
Bug 1793463 - Part 5: Stop using contractids to fetch protocol handlers, r=necko-reviewers,xpcom-reviewers,webdriver-reviewers,whimboo,valentin,kmag
This patch replaces the previous ContractID-based lookup system for protocol handlers, and replaces it with a new custom system in nsIOService. It will be pre-populated with non-overridable static protocol handlers using the StaticComponents infrastructure added in the previous part, and callers can also dynamically register new protocol handlers at runtime. This new system is intended to provide access to the default port and non-dynamic protocol flags off-main-thread, by requiring these values to be provided up-front as constants, rather than getting them from the xpcom interface. The data is then guarded by an RWLock. Callers which look up specific handlers by their contractID are not changed, as the contract IDs for existing handlers have not been changed, so the lookup will still succeed. This change as-implemented breaks the nsGIOProtocolHandler on Linux, as it removes the special code which would try to use that handler for some protocols. This will be fixed in a later part by making the nsGIOProtocolHandler use the dynamic registration APIs to register and un-register protocol handlers at runtime in response to the GIO pref. Differential Revision: https://phabricator.services.mozilla.com/D162804
This commit is contained in:
parent
bca0a6965b
commit
98304d1200
@ -104,13 +104,7 @@ function getTopWin({ skipPopups, forceNonPrivate } = {}) {
|
||||
}
|
||||
|
||||
function doGetProtocolFlags(aURI) {
|
||||
let handler = Services.io.getProtocolHandler(aURI.scheme);
|
||||
// see DoGetProtocolFlags in nsIProtocolHandler.idl
|
||||
return handler instanceof Ci.nsIProtocolHandlerWithDynamicFlags
|
||||
? handler
|
||||
.QueryInterface(Ci.nsIProtocolHandlerWithDynamicFlags)
|
||||
.getFlagsForURI(aURI)
|
||||
: handler.protocolFlags;
|
||||
return Services.io.getDynamicProtocolFlags(aURI);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -7,14 +7,11 @@
|
||||
var manifests = [do_get_file("data/test_no_remote_registration.manifest")];
|
||||
registerManifests(manifests);
|
||||
|
||||
function ProtocolHandler(aScheme, aFlags) {
|
||||
function ProtocolHandler(aScheme) {
|
||||
this.scheme = aScheme;
|
||||
this.protocolFlags = aFlags;
|
||||
this.contractID = "@mozilla.org/network/protocol;1?name=" + aScheme;
|
||||
}
|
||||
|
||||
ProtocolHandler.prototype = {
|
||||
defaultPort: -1,
|
||||
allowPort: () => false,
|
||||
newChannel() {
|
||||
throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
|
||||
@ -28,7 +25,6 @@ var testProtocols = [
|
||||
{
|
||||
scheme: "moz-protocol-ui-resource",
|
||||
flags: Ci.nsIProtocolHandler.URI_IS_UI_RESOURCE,
|
||||
CID: Components.ID("{d6dedc93-558f-44fe-90f4-3b4bba8a0b14}"),
|
||||
shouldRegister: false,
|
||||
},
|
||||
// It doesn't matter if it has this flag - the only flag we accept is
|
||||
@ -36,21 +32,18 @@ var testProtocols = [
|
||||
{
|
||||
scheme: "moz-protocol-local-file",
|
||||
flags: Ci.nsIProtocolHandler.URI_IS_LOCAL_FILE,
|
||||
CID: Components.ID("{ee30d594-0a2d-4f47-89cc-d4cde320ab69}"),
|
||||
shouldRegister: false,
|
||||
},
|
||||
// This clearly is non-local
|
||||
{
|
||||
scheme: "moz-protocol-loadable-by-anyone",
|
||||
flags: Ci.nsIProtocolHandler.URI_LOADABLE_BY_ANYONE,
|
||||
CID: Components.ID("{c3735f23-3b0c-4a33-bfa0-79436dcd40b2}"),
|
||||
shouldRegister: false,
|
||||
},
|
||||
// This should always be last (unless we add more flags that are OK)
|
||||
{
|
||||
scheme: "moz-protocol-local-resource",
|
||||
flags: Ci.nsIProtocolHandler.URI_IS_LOCAL_RESOURCE,
|
||||
CID: Components.ID("{b79e977c-f840-469a-b413-0125cc1b62a5}"),
|
||||
shouldRegister: true,
|
||||
},
|
||||
];
|
||||
@ -77,35 +70,17 @@ function run_test() {
|
||||
},
|
||||
};
|
||||
|
||||
let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
|
||||
// Create factories
|
||||
let factories = [];
|
||||
for (let i = 0; i < testProtocols.length; i++) {
|
||||
factories[i] = {
|
||||
scheme: testProtocols[i].scheme,
|
||||
flags: testProtocols[i].flags,
|
||||
CID: testProtocols[i].CID,
|
||||
contractID:
|
||||
"@mozilla.org/network/protocol;1?name=" + testProtocols[i].scheme,
|
||||
createInstance(aIID) {
|
||||
let handler = new ProtocolHandler(this.scheme, this.flags, this.CID);
|
||||
return handler.QueryInterface(aIID);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// Register our factories
|
||||
for (let i = 0; i < factories.length; i++) {
|
||||
let factory = factories[i];
|
||||
registrar.registerFactory(
|
||||
factory.CID,
|
||||
"test-" + factory.scheme,
|
||||
factory.contractID,
|
||||
factory
|
||||
for (let protocol of testProtocols) {
|
||||
Services.io.registerProtocolHandler(
|
||||
protocol.scheme,
|
||||
new ProtocolHandler(protocol.scheme),
|
||||
protocol.flags,
|
||||
-1
|
||||
);
|
||||
}
|
||||
|
||||
let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
|
||||
// Register the XULAppInfoFactory
|
||||
// Make sure the class ID has not already been registered
|
||||
let old_factory = { CID: "", factory: null };
|
||||
@ -209,10 +184,9 @@ function run_test() {
|
||||
}
|
||||
}
|
||||
|
||||
// Unregister our factories so we do not leak
|
||||
for (let i = 0; i < factories.length; i++) {
|
||||
let factory = factories[i];
|
||||
registrar.unregisterFactory(factory.CID, factory);
|
||||
// Unregister our protocol handlers so we do not leak
|
||||
for (let protocol of testProtocols) {
|
||||
Services.io.unregisterProtocolHandler(protocol.scheme);
|
||||
}
|
||||
|
||||
// Unregister XULAppInfoFactory
|
||||
|
@ -99,14 +99,6 @@ CustomProtocol.prototype = {
|
||||
get scheme() {
|
||||
return PROTOCOL_SCHEME;
|
||||
},
|
||||
get protocolFlags() {
|
||||
return (Ci.nsIProtocolHandler.URI_NORELATIVE |
|
||||
Ci.nsIProtocolHandler.URI_IS_LOCAL_RESOURCE |
|
||||
Ci.nsIProtocolHandler.URI_DANGEROUS_TO_LOAD);
|
||||
},
|
||||
get defaultPort() {
|
||||
return -1;
|
||||
},
|
||||
allowPort: function allowPort() {
|
||||
return false;
|
||||
},
|
||||
@ -118,17 +110,17 @@ CustomProtocol.prototype = {
|
||||
|
||||
var gFactory = {
|
||||
register() {
|
||||
var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
|
||||
var classID = Components.ID("{ed064287-1e76-49ba-a28d-dc74394a8334}");
|
||||
var description = PROTOCOL_SCHEME + ": protocol";
|
||||
var contractID = "@mozilla.org/network/protocol;1?name=" + PROTOCOL_SCHEME;
|
||||
var factory = ComponentUtils.generateSingletonFactory(CustomProtocol);
|
||||
|
||||
registrar.registerFactory(classID, description, contractID, factory);
|
||||
Services.io.registerProtocolHandler(
|
||||
PROTOCOL_SCHEME,
|
||||
new CustomProtocol(),
|
||||
Ci.nsIProtocolHandler.URI_NORELATIVE |
|
||||
Ci.nsIProtocolHandler.URI_IS_LOCAL_RESOURCE |
|
||||
Ci.nsIProtocolHandler.URI_DANGEROUS_TO_LOAD,
|
||||
-1
|
||||
);
|
||||
|
||||
this.unregister = function() {
|
||||
registrar.unregisterFactory(classID, factory);
|
||||
Services.io.unregisterProtocolHandler(PROTOCOL_SCHEME);
|
||||
delete this.unregister;
|
||||
};
|
||||
},
|
||||
|
@ -18,10 +18,7 @@ var uris = [
|
||||
function run_test() {
|
||||
for (let i = 0; i < uris.length; i++) {
|
||||
let uri = ios.newURI(uris[i].uri);
|
||||
let handler = ios
|
||||
.getProtocolHandler(uri.scheme)
|
||||
.QueryInterface(Ci.nsIProtocolHandler);
|
||||
let flags = handler.protocolFlags;
|
||||
let flags = ios.getDynamicProtocolFlags(uri);
|
||||
|
||||
Assert.equal(
|
||||
Ci.nsIProtocolHandler.URI_IS_LOCAL_RESOURCE & flags,
|
||||
|
@ -1261,19 +1261,11 @@ nsresult nsContentSecurityManager::CheckChannelHasProtocolSecurityFlag(
|
||||
nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoCString scheme;
|
||||
rv = uri->GetScheme(scheme);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIIOService> ios = do_GetIOService(&rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIProtocolHandler> handler;
|
||||
rv = ios->GetProtocolHandler(scheme.get(), getter_AddRefs(handler));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
uint32_t flags;
|
||||
rv = handler->DoGetProtocolFlags(uri, &flags);
|
||||
rv = ios->GetDynamicProtocolFlags(uri, &flags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
uint32_t securityFlagsSet = 0;
|
||||
|
86
netwerk/base/ProtocolHandlerInfo.cpp
Normal file
86
netwerk/base/ProtocolHandlerInfo.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#include "ProtocolHandlerInfo.h"
|
||||
#include "StaticComponents.h"
|
||||
#include "nsIProtocolHandler.h"
|
||||
|
||||
namespace mozilla::net {
|
||||
|
||||
uint32_t ProtocolHandlerInfo::StaticProtocolFlags() const {
|
||||
uint32_t flags = mInner.match(
|
||||
[&](const xpcom::StaticProtocolHandler* handler) {
|
||||
return handler->mProtocolFlags;
|
||||
},
|
||||
[&](const RuntimeProtocolHandler& handler) {
|
||||
return handler.mProtocolFlags;
|
||||
});
|
||||
#if !IS_ORIGIN_IS_FULL_SPEC_DEFINED
|
||||
MOZ_RELEASE_ASSERT(!(flags & nsIProtocolHandler::ORIGIN_IS_FULL_SPEC),
|
||||
"ORIGIN_IS_FULL_SPEC is unsupported but used");
|
||||
#endif
|
||||
return flags;
|
||||
}
|
||||
|
||||
int32_t ProtocolHandlerInfo::DefaultPort() const {
|
||||
return mInner.match(
|
||||
[&](const xpcom::StaticProtocolHandler* handler) {
|
||||
return handler->mDefaultPort;
|
||||
},
|
||||
[&](const RuntimeProtocolHandler& handler) {
|
||||
return handler.mDefaultPort;
|
||||
});
|
||||
}
|
||||
|
||||
nsresult ProtocolHandlerInfo::DynamicProtocolFlags(nsIURI* aURI,
|
||||
uint32_t* aFlags) const {
|
||||
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
|
||||
|
||||
// If we're querying dynamic flags, we'll need to fetch the actual xpcom
|
||||
// component in order to check them.
|
||||
if (HasDynamicFlags()) {
|
||||
nsCOMPtr<nsIProtocolHandler> handler = Handler();
|
||||
if (nsCOMPtr<nsIProtocolHandlerWithDynamicFlags> dynamic =
|
||||
do_QueryInterface(handler)) {
|
||||
nsresult rv = dynamic->GetFlagsForURI(aURI, aFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
MOZ_DIAGNOSTIC_ASSERT(
|
||||
(StaticProtocolFlags() & ~nsIProtocolHandler::DYNAMIC_URI_FLAGS) ==
|
||||
(*aFlags & ~nsIProtocolHandler::DYNAMIC_URI_FLAGS),
|
||||
"only DYNAMIC_URI_FLAGS may be changed by a "
|
||||
"nsIProtocolHandlerWithDynamicFlags implementation");
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, just check against static flags.
|
||||
*aFlags = StaticProtocolFlags();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool ProtocolHandlerInfo::HasDynamicFlags() const {
|
||||
return mInner.match(
|
||||
[&](const xpcom::StaticProtocolHandler* handler) {
|
||||
return handler->mHasDynamicFlags;
|
||||
},
|
||||
[&](const RuntimeProtocolHandler&) { return false; });
|
||||
}
|
||||
|
||||
already_AddRefed<nsIProtocolHandler> ProtocolHandlerInfo::Handler() const {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsCOMPtr<nsIProtocolHandler> retval;
|
||||
mInner.match(
|
||||
[&](const xpcom::StaticProtocolHandler* handler) {
|
||||
retval = handler->Module().GetService();
|
||||
},
|
||||
[&](const RuntimeProtocolHandler& handler) {
|
||||
retval = handler.mHandler.get();
|
||||
});
|
||||
return retval.forget();
|
||||
}
|
||||
|
||||
} // namespace mozilla::net
|
67
netwerk/base/ProtocolHandlerInfo.h
Normal file
67
netwerk/base/ProtocolHandlerInfo.h
Normal file
@ -0,0 +1,67 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_net_ProtocolHandlerInfo_h
|
||||
#define mozilla_net_ProtocolHandlerInfo_h
|
||||
|
||||
#include "mozilla/Variant.h"
|
||||
#include "nsProxyRelease.h"
|
||||
#include "nsIProtocolHandler.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace xpcom {
|
||||
struct StaticProtocolHandler;
|
||||
}
|
||||
|
||||
namespace net {
|
||||
|
||||
struct RuntimeProtocolHandler {
|
||||
nsMainThreadPtrHandle<nsIProtocolHandler> mHandler;
|
||||
uint32_t mProtocolFlags;
|
||||
int32_t mDefaultPort;
|
||||
};
|
||||
|
||||
// Information about a specific protocol handler.
|
||||
class ProtocolHandlerInfo {
|
||||
public:
|
||||
explicit ProtocolHandlerInfo(const xpcom::StaticProtocolHandler& aStatic)
|
||||
: mInner(AsVariant(&aStatic)) {}
|
||||
explicit ProtocolHandlerInfo(RuntimeProtocolHandler aDynamic)
|
||||
: mInner(AsVariant(std::move(aDynamic))) {}
|
||||
|
||||
// Returns the statically known protocol-specific flags.
|
||||
// See `nsIProtocolHandler` for valid values.
|
||||
uint32_t StaticProtocolFlags() const;
|
||||
|
||||
// The port that this protocol normally uses.
|
||||
// If a port does not make sense for the protocol (e.g., "about:") then -1
|
||||
// will be returned.
|
||||
int32_t DefaultPort() const;
|
||||
|
||||
// If true, `DynamicProtocolFlags()` may return a different value than
|
||||
// `StaticProtocolFlags()` for flags in `DYNAMIC_URI_FLAGS`, due to a
|
||||
// `nsIProtocolHandlerWithDynamicFlags` implementation.
|
||||
bool HasDynamicFlags() const;
|
||||
|
||||
// Like `StaticProtocolFlags()` but also checks
|
||||
// `nsIProtocolHandlerWithDynamicFlags` for uri-specific flags.
|
||||
//
|
||||
// NOTE: Only safe to call from the main thread.
|
||||
nsresult DynamicProtocolFlags(nsIURI* aURI, uint32_t* aFlags) const
|
||||
MOZ_REQUIRES(sMainThreadCapability);
|
||||
|
||||
// Get the main-thread-only nsIProtocolHandler instance.
|
||||
already_AddRefed<nsIProtocolHandler> Handler() const
|
||||
MOZ_REQUIRES(sMainThreadCapability);
|
||||
|
||||
private:
|
||||
Variant<const xpcom::StaticProtocolHandler*, RuntimeProtocolHandler> mInner;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_net_ProtocolHandlerInfo_h
|
@ -166,6 +166,7 @@ EXPORTS.mozilla.net += [
|
||||
"NetworkConnectivityService.h",
|
||||
"Predictor.h",
|
||||
"PrivateBrowsingChannel.h",
|
||||
"ProtocolHandlerInfo.h",
|
||||
"RedirectChannelRegistrar.h",
|
||||
"RequestContextService.h",
|
||||
"SimpleChannelParent.h",
|
||||
@ -231,6 +232,7 @@ UNIFIED_SOURCES += [
|
||||
"nsUDPSocket.cpp",
|
||||
"PollableEvent.cpp",
|
||||
"Predictor.cpp",
|
||||
"ProtocolHandlerInfo.cpp",
|
||||
"ProxyAutoConfig.cpp",
|
||||
"RedirectChannelRegistrar.cpp",
|
||||
"RequestContextService.cpp",
|
||||
@ -310,6 +312,7 @@ include("/ipc/chromium/chromium-config.mozbuild")
|
||||
FINAL_LIBRARY = "xul"
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
"!/xpcom/components",
|
||||
"/docshell/base",
|
||||
"/dom/base",
|
||||
"/netwerk/dns",
|
||||
@ -318,6 +321,7 @@ LOCAL_INCLUDES += [
|
||||
"/netwerk/socket",
|
||||
"/netwerk/url-classifier",
|
||||
"/security/manager/ssl",
|
||||
"/xpcom/components",
|
||||
]
|
||||
|
||||
if CONFIG["MOZ_WIDGET_TOOLKIT"] == "cocoa":
|
||||
|
@ -54,17 +54,30 @@ interface nsIIOService : nsISupports
|
||||
* Returns the protocol flags for a given scheme.
|
||||
*
|
||||
* @param aScheme the URI scheme
|
||||
* @return value of corresponding nsIProtocolHandler::protocolFlags
|
||||
* @return protocol flags for the corresponding protocol
|
||||
*/
|
||||
unsigned long getProtocolFlags(in string aScheme);
|
||||
|
||||
/**
|
||||
* This method constructs a new URI by determining the scheme of the
|
||||
* URI spec, and then delegating the construction of the URI to the
|
||||
* protocol handler for that scheme. QueryInterface can be used on
|
||||
* the resulting URI object to obtain a more specific type of URI.
|
||||
* Returns the dynamic protocol flags for a given URI.
|
||||
*
|
||||
* @see nsIProtocolHandler::newURI
|
||||
* @param aURI the URI to get all dynamic flags for
|
||||
* @return protocol flags for that URI
|
||||
*/
|
||||
unsigned long getDynamicProtocolFlags(in nsIURI aURI);
|
||||
|
||||
/**
|
||||
* Returns the default port for a given scheme.
|
||||
*
|
||||
* @param aScheme the URI scheme
|
||||
* @return default port for the corresponding protocol
|
||||
*/
|
||||
long getDefaultPort(in string aScheme);
|
||||
|
||||
/**
|
||||
* This method constructs a new URI based on the scheme of the URI spec.
|
||||
* QueryInterface can be used on the resulting URI object to obtain a more
|
||||
* specific type of URI.
|
||||
*/
|
||||
nsIURI newURI(in AUTF8String aSpec,
|
||||
[optional] in string aOriginCharset,
|
||||
@ -270,6 +283,35 @@ interface nsIIOService : nsISupports
|
||||
* The pid for socket process.
|
||||
*/
|
||||
readonly attribute unsigned long long socketProcessId;
|
||||
|
||||
/**
|
||||
* Register a protocol handler at runtime, given protocol flags and a
|
||||
* default port.
|
||||
*
|
||||
* Statically registered protocol handlers cannot be overridden, and an
|
||||
* error will be returned if that is attempted.
|
||||
*
|
||||
* Runtime registered protocol handlers are never QueryInterface-ed into
|
||||
* `nsIProtocolHandlerWithDynamicFlags`, so that interface will be ignored.
|
||||
*
|
||||
* @param aScheme the scheme handled by the protocol handler.
|
||||
* @param aHandler the protocol handler instance.
|
||||
* @param aProtocolFlags protocol flags for this protocol, see
|
||||
* nsIProtocolHandler for values.
|
||||
* @param aDefaultPort default port for this scheme, or -1.
|
||||
*/
|
||||
void registerProtocolHandler(in ACString aScheme,
|
||||
in nsIProtocolHandler aHandler,
|
||||
in unsigned long aProtocolFlags,
|
||||
in long aDefaultPort);
|
||||
|
||||
/**
|
||||
* Unregister a protocol handler which was previously registered using
|
||||
* registerProtocolHandler.
|
||||
*
|
||||
* @param aScheme the scheme to unregister a handler for.
|
||||
*/
|
||||
void unregisterProtocolHandler(in ACString aScheme);
|
||||
};
|
||||
|
||||
%{C++
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "nsNetCID.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsSimpleNestedURI.h"
|
||||
#include "nsSocketTransport2.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsIConsoleService.h"
|
||||
#include "nsIUploadChannel2.h"
|
||||
@ -64,10 +65,7 @@
|
||||
#include "mozilla/StaticPrefs_security.h"
|
||||
#include "nsNSSComponent.h"
|
||||
#include "ssl.h"
|
||||
|
||||
#ifdef MOZ_WIDGET_GTK
|
||||
# include "nsGIOProtocolHandler.h"
|
||||
#endif
|
||||
#include "StaticComponents.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
@ -88,6 +86,7 @@ using mozilla::dom::ServiceWorkerDescriptor;
|
||||
#define NETWORK_CAPTIVE_PORTAL_PREF "network.captive-portal-service.enabled"
|
||||
#define WEBRTC_PREF_PREFIX "media.peerconnection."
|
||||
#define NETWORK_DNS_PREF "network.dns."
|
||||
#define FORCE_EXTERNAL_PREF_PREFIX "network.protocol-handler.external."
|
||||
|
||||
#define MAX_RECURSION_COUNT 50
|
||||
|
||||
@ -213,6 +212,7 @@ static const char* gCallbackPrefs[] = {
|
||||
NECKO_BUFFER_CACHE_COUNT_PREF,
|
||||
NECKO_BUFFER_CACHE_SIZE_PREF,
|
||||
NETWORK_CAPTIVE_PORTAL_PREF,
|
||||
FORCE_EXTERNAL_PREF_PREFIX,
|
||||
nullptr,
|
||||
};
|
||||
|
||||
@ -846,121 +846,65 @@ nsresult nsIOService::AsyncOnChannelRedirect(
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsIOService::CacheProtocolHandler(const char* scheme,
|
||||
nsIProtocolHandler* handler) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
for (unsigned int i = 0; i < NS_N(gScheme); i++) {
|
||||
if (!nsCRT::strcasecmp(scheme, gScheme[i])) {
|
||||
nsresult rv;
|
||||
NS_ASSERTION(!mWeakHandler[i], "Protocol handler already cached");
|
||||
// Make sure the handler supports weak references.
|
||||
nsCOMPtr<nsISupportsWeakReference> factoryPtr =
|
||||
do_QueryInterface(handler, &rv);
|
||||
if (!factoryPtr) {
|
||||
// Don't cache handlers that don't support weak reference as
|
||||
// there is real danger of a circular reference.
|
||||
#ifdef DEBUG_dp
|
||||
printf(
|
||||
"DEBUG: %s protcol handler doesn't support weak ref. Not cached.\n",
|
||||
scheme);
|
||||
#endif /* DEBUG_dp */
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mWeakHandler[i] = do_GetWeakReference(handler);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult nsIOService::GetCachedProtocolHandler(const char* scheme,
|
||||
nsIProtocolHandler** result,
|
||||
uint32_t start, uint32_t end) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
uint32_t len = end - start - 1;
|
||||
for (unsigned int i = 0; i < NS_N(gScheme); i++) {
|
||||
if (!mWeakHandler[i]) continue;
|
||||
|
||||
// handle unterminated strings
|
||||
// start is inclusive, end is exclusive, len = end - start - 1
|
||||
if (end ? (!nsCRT::strncasecmp(scheme + start, gScheme[i], len) &&
|
||||
gScheme[i][len] == '\0')
|
||||
: (!nsCRT::strcasecmp(scheme, gScheme[i]))) {
|
||||
return CallQueryReferent(mWeakHandler[i].get(), result);
|
||||
}
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
static bool UsesExternalProtocolHandler(const char* aScheme) {
|
||||
if ("file"_ns.Equals(aScheme) || "chrome"_ns.Equals(aScheme) ||
|
||||
"resource"_ns.Equals(aScheme)) {
|
||||
bool nsIOService::UsesExternalProtocolHandler(const nsACString& aScheme) {
|
||||
if (aScheme == "file"_ns || aScheme == "chrome"_ns ||
|
||||
aScheme == "resource"_ns) {
|
||||
// Don't allow file:, chrome: or resource: URIs to be handled with
|
||||
// nsExternalProtocolHandler, since internally we rely on being able to
|
||||
// use and read from these URIs.
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto& forcedExternalScheme : gForcedExternalSchemes) {
|
||||
if (!nsCRT::strcasecmp(forcedExternalScheme, aScheme)) {
|
||||
if (aScheme == "place"_ns || aScheme == "fake-favicon-uri"_ns ||
|
||||
aScheme == "favicon"_ns || aScheme == "moz-nullprincipal"_ns) {
|
||||
// Force place: fake-favicon-uri: favicon: and moz-nullprincipal: URIs to be
|
||||
// handled with nsExternalProtocolHandler, and not with a dynamically
|
||||
// registered handler.
|
||||
return true;
|
||||
}
|
||||
|
||||
// If prefs configure the URI to be handled externally, do so.
|
||||
for (const auto& scheme : mForceExternalSchemes) {
|
||||
if (aScheme == scheme) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoCString pref("network.protocol-handler.external.");
|
||||
pref += aScheme;
|
||||
ProtocolHandlerInfo nsIOService::LookupProtocolHandler(
|
||||
const nsACString& aScheme) {
|
||||
// Look-ups are ASCII-case-insensitive, so lower-case the string before
|
||||
// continuing.
|
||||
nsAutoCString scheme(aScheme);
|
||||
ToLowerCase(scheme);
|
||||
|
||||
return Preferences::GetBool(pref.get(), false);
|
||||
// NOTE: If we could get rid of mForceExternalSchemes (or prevent them from
|
||||
// disabling static protocols), we could avoid locking mLock until we need to
|
||||
// check `mRuntimeProtocolHandlers.
|
||||
AutoReadLock lock(mLock);
|
||||
if (!UsesExternalProtocolHandler(scheme)) {
|
||||
// Try the static protocol handler first - they cannot be overridden by
|
||||
// dynamic protocols.
|
||||
if (const xpcom::StaticProtocolHandler* handler =
|
||||
xpcom::StaticProtocolHandler::Lookup(scheme)) {
|
||||
return ProtocolHandlerInfo(*handler);
|
||||
}
|
||||
if (auto handler = mRuntimeProtocolHandlers.Lookup(scheme)) {
|
||||
return ProtocolHandlerInfo(handler.Data());
|
||||
}
|
||||
}
|
||||
return ProtocolHandlerInfo(xpcom::StaticProtocolHandler::Default());
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsIOService::GetProtocolHandler(const char* scheme,
|
||||
nsIProtocolHandler** result) {
|
||||
nsresult rv;
|
||||
|
||||
AssertIsOnMainThread();
|
||||
NS_ENSURE_ARG_POINTER(scheme);
|
||||
// XXX we may want to speed this up by introducing our own protocol
|
||||
// scheme -> protocol handler mapping, avoiding the string manipulation
|
||||
// and service manager stuff
|
||||
|
||||
rv = GetCachedProtocolHandler(scheme, result);
|
||||
if (NS_SUCCEEDED(rv)) return rv;
|
||||
|
||||
if (scheme[0] != '\0' && !UsesExternalProtocolHandler(scheme)) {
|
||||
nsAutoCString contractID(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX);
|
||||
contractID += scheme;
|
||||
ToLowerCase(contractID);
|
||||
|
||||
rv = CallGetService(contractID.get(), result);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
CacheProtocolHandler(scheme, *result);
|
||||
return rv;
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_GTK
|
||||
// check to see whether GVFS can handle this URI scheme. otherwise, we
|
||||
// failover to using the default protocol handler.
|
||||
|
||||
RefPtr<nsGIOProtocolHandler> gioHandler =
|
||||
nsGIOProtocolHandler::GetSingleton();
|
||||
if (gioHandler->IsSupportedProtocol(nsCString(scheme))) {
|
||||
gioHandler.forget(result);
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Okay we don't have a protocol handler to handle this url type, so use
|
||||
// the default protocol handler. This will cause urls to get dispatched
|
||||
// out to the OS ('cause we can't do anything with them) when we try to
|
||||
// read from a channel created by the default protocol handler.
|
||||
|
||||
rv = CallGetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "default", result);
|
||||
if (NS_FAILED(rv)) return NS_ERROR_UNKNOWN_PROTOCOL;
|
||||
|
||||
return rv;
|
||||
*result = LookupProtocolHandler(nsDependentCString(scheme)).Handler().take();
|
||||
return *result ? NS_OK : NS_ERROR_UNKNOWN_PROTOCOL;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -1016,19 +960,32 @@ nsIOService::HostnameIsSharedIPAddress(nsIURI* aURI, bool* aResult) {
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsIOService::GetProtocolFlags(const char* scheme, uint32_t* flags) {
|
||||
nsCOMPtr<nsIProtocolHandler> handler;
|
||||
nsresult rv = GetProtocolHandler(scheme, getter_AddRefs(handler));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
NS_ENSURE_ARG_POINTER(scheme);
|
||||
|
||||
// We can't call DoGetProtocolFlags here because we don't have a URI. This
|
||||
// API is used by (and only used by) extensions, which is why it's still
|
||||
// around. Calling this on a scheme with dynamic flags will throw.
|
||||
rv = handler->GetProtocolFlags(flags);
|
||||
#if !IS_ORIGIN_IS_FULL_SPEC_DEFINED
|
||||
MOZ_RELEASE_ASSERT(!(*flags & nsIProtocolHandler::ORIGIN_IS_FULL_SPEC),
|
||||
"ORIGIN_IS_FULL_SPEC is unsupported but used");
|
||||
#endif
|
||||
return rv;
|
||||
*flags =
|
||||
LookupProtocolHandler(nsDependentCString(scheme)).StaticProtocolFlags();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsIOService::GetDynamicProtocolFlags(nsIURI* uri, uint32_t* flags) {
|
||||
AssertIsOnMainThread();
|
||||
NS_ENSURE_ARG(uri);
|
||||
|
||||
nsAutoCString scheme;
|
||||
nsresult rv = uri->GetScheme(scheme);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return LookupProtocolHandler(scheme).DynamicProtocolFlags(uri, flags);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsIOService::GetDefaultPort(const char* scheme, int32_t* defaultPort) {
|
||||
NS_ENSURE_ARG_POINTER(scheme);
|
||||
|
||||
*defaultPort =
|
||||
LookupProtocolHandler(nsDependentCString(scheme)).DefaultPort();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class AutoIncrement {
|
||||
@ -1156,10 +1113,6 @@ nsresult nsIOService::NewChannelFromURIWithProxyFlagsInternal(
|
||||
rv = GetProtocolHandler(scheme.get(), getter_AddRefs(handler));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
uint32_t protoFlags;
|
||||
rv = handler->DoGetProtocolFlags(aURI, &protoFlags);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
nsCOMPtr<nsIProxiedProtocolHandler> pph = do_QueryInterface(handler);
|
||||
if (pph) {
|
||||
@ -1464,7 +1417,7 @@ nsIOService::AllowPort(int32_t inPort, const char* scheme, bool* _retval) {
|
||||
|
||||
nsTArray<int32_t> restrictedPortList;
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
AutoReadLock lock(mLock);
|
||||
restrictedPortList.Assign(mRestrictedPortList);
|
||||
}
|
||||
// first check to see if the port is in our blacklist:
|
||||
@ -1558,13 +1511,30 @@ void nsIOService::PrefsChanged(const char* pref) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!pref || strncmp(pref, FORCE_EXTERNAL_PREF_PREFIX,
|
||||
strlen(FORCE_EXTERNAL_PREF_PREFIX)) == 0) {
|
||||
nsTArray<nsCString> prefs;
|
||||
if (nsIPrefBranch* prefRootBranch = Preferences::GetRootBranch()) {
|
||||
prefRootBranch->GetChildList(FORCE_EXTERNAL_PREF_PREFIX, prefs);
|
||||
}
|
||||
nsTArray<nsCString> forceExternalSchemes;
|
||||
for (const auto& pref : prefs) {
|
||||
if (Preferences::GetBool(pref.get(), false)) {
|
||||
forceExternalSchemes.AppendElement(
|
||||
Substring(pref, strlen(FORCE_EXTERNAL_PREF_PREFIX)));
|
||||
}
|
||||
}
|
||||
AutoWriteLock lock(mLock);
|
||||
mForceExternalSchemes = std::move(forceExternalSchemes);
|
||||
}
|
||||
}
|
||||
|
||||
void nsIOService::ParsePortList(const char* pref, bool remove) {
|
||||
nsAutoCString portList;
|
||||
nsTArray<int32_t> restrictedPortList;
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
AutoWriteLock lock(mLock);
|
||||
restrictedPortList.Assign(std::move(mRestrictedPortList));
|
||||
}
|
||||
// Get a pref string and chop it up into a list of ports.
|
||||
@ -1605,7 +1575,7 @@ void nsIOService::ParsePortList(const char* pref, bool remove) {
|
||||
}
|
||||
}
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
AutoWriteLock lock(mLock);
|
||||
mRestrictedPortList.Assign(std::move(restrictedPortList));
|
||||
}
|
||||
|
||||
@ -1713,6 +1683,13 @@ nsIOService::Observe(nsISupports* subject, const char* topic,
|
||||
gCallbackSecurityPrefs, this);
|
||||
PrepareForShutdownInSocketProcess();
|
||||
}
|
||||
|
||||
// We're in XPCOM shutdown now. Unregister any dynamic protocol handlers
|
||||
// after this point to avoid leaks.
|
||||
{
|
||||
AutoWriteLock lock(mLock);
|
||||
mRuntimeProtocolHandlers.Clear();
|
||||
}
|
||||
} else if (!strcmp(topic, NS_NETWORK_LINK_TOPIC)) {
|
||||
OnNetworkLinkEvent(NS_ConvertUTF16toUTF8(data).get());
|
||||
} else if (!strcmp(topic, NS_NETWORK_ID_CHANGED_TOPIC)) {
|
||||
@ -1755,13 +1732,16 @@ nsIOService::ProtocolHasFlags(nsIURI* uri, uint32_t flags, bool* result) {
|
||||
nsresult rv = uri->GetScheme(scheme);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Grab the protocol flags from the URI.
|
||||
auto handler = LookupProtocolHandler(scheme);
|
||||
|
||||
uint32_t protocolFlags;
|
||||
nsCOMPtr<nsIProtocolHandler> handler;
|
||||
rv = GetProtocolHandler(scheme.get(), getter_AddRefs(handler));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = handler->DoGetProtocolFlags(uri, &protocolFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (flags & nsIProtocolHandler::DYNAMIC_URI_FLAGS) {
|
||||
AssertIsOnMainThread();
|
||||
rv = handler.DynamicProtocolFlags(uri, &protocolFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else {
|
||||
protocolFlags = handler.StaticProtocolFlags();
|
||||
}
|
||||
|
||||
*result = (protocolFlags & flags) == flags;
|
||||
return NS_OK;
|
||||
@ -2121,5 +2101,60 @@ nsIOService::GetSocketProcessId(uint64_t* aPid) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsIOService::RegisterProtocolHandler(const nsACString& aScheme,
|
||||
nsIProtocolHandler* aHandler,
|
||||
uint32_t aProtocolFlags,
|
||||
int32_t aDefaultPort) {
|
||||
if (mShutdown) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
if (aScheme.IsEmpty()) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsAutoCString scheme(aScheme);
|
||||
ToLowerCase(scheme);
|
||||
|
||||
AutoWriteLock lock(mLock);
|
||||
return mRuntimeProtocolHandlers.WithEntryHandle(scheme, [&](auto&& entry) {
|
||||
if (entry) {
|
||||
NS_WARNING("Cannot override an existing dynamic protocol handler");
|
||||
return NS_ERROR_FACTORY_EXISTS;
|
||||
}
|
||||
if (xpcom::StaticProtocolHandler::Lookup(scheme)) {
|
||||
NS_WARNING("Cannot override an existing static protocol handler");
|
||||
return NS_ERROR_FACTORY_EXISTS;
|
||||
}
|
||||
nsMainThreadPtrHandle<nsIProtocolHandler> handler(
|
||||
new nsMainThreadPtrHolder<nsIProtocolHandler>("RuntimeProtocolHandler",
|
||||
aHandler));
|
||||
entry.Insert(RuntimeProtocolHandler{
|
||||
.mHandler = std::move(handler),
|
||||
.mProtocolFlags = aProtocolFlags,
|
||||
.mDefaultPort = aDefaultPort,
|
||||
});
|
||||
return NS_OK;
|
||||
});
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsIOService::UnregisterProtocolHandler(const nsACString& aScheme) {
|
||||
if (mShutdown) {
|
||||
return NS_OK;
|
||||
}
|
||||
if (aScheme.IsEmpty()) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsAutoCString scheme(aScheme);
|
||||
ToLowerCase(scheme);
|
||||
|
||||
AutoWriteLock lock(mLock);
|
||||
return mRuntimeProtocolHandlers.Remove(scheme)
|
||||
? NS_OK
|
||||
: NS_ERROR_FACTORY_NOT_REGISTERED;
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
@ -19,7 +19,8 @@
|
||||
#include "nsWeakReference.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/RWLock.h"
|
||||
#include "mozilla/net/ProtocolHandlerInfo.h"
|
||||
#include "prtime.h"
|
||||
#include "nsICaptivePortalService.h"
|
||||
#include "nsIObserverService.h"
|
||||
@ -35,14 +36,6 @@
|
||||
#define NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC "ipc:network:set-offline"
|
||||
#define NS_IPC_IOSERVICE_SET_CONNECTIVITY_TOPIC "ipc:network:set-connectivity"
|
||||
|
||||
static const char gScheme[][sizeof("moz-safe-about")] = {
|
||||
"chrome", "file", "http", "https",
|
||||
"jar", "data", "about", "moz-safe-about",
|
||||
"resource", "moz-extension", "page-icon", "blob"};
|
||||
|
||||
static const char gForcedExternalSchemes[][sizeof("moz-nullprincipal")] = {
|
||||
"place", "fake-favicon-uri", "favicon", "moz-nullprincipal"};
|
||||
|
||||
class nsINetworkLinkService;
|
||||
class nsIPrefBranch;
|
||||
class nsIProtocolProxyService2;
|
||||
@ -142,6 +135,10 @@ class nsIOService final : public nsIIOService,
|
||||
friend SocketProcessMemoryReporter;
|
||||
RefPtr<MemoryReportingProcess> GetSocketProcessMemoryReporter();
|
||||
|
||||
// Lookup the ProtocolHandlerInfo based on a given scheme.
|
||||
// Safe to call from any thread.
|
||||
ProtocolHandlerInfo LookupProtocolHandler(const nsACString& aScheme);
|
||||
|
||||
static void OnTLSPrefChange(const char* aPref, void* aSelf);
|
||||
|
||||
nsresult LaunchSocketProcess();
|
||||
@ -159,12 +156,6 @@ class nsIOService final : public nsIIOService,
|
||||
|
||||
nsresult OnNetworkLinkEvent(const char* data);
|
||||
|
||||
nsresult GetCachedProtocolHandler(const char* scheme,
|
||||
nsIProtocolHandler** hdlrResult,
|
||||
uint32_t start = 0, uint32_t end = 0);
|
||||
nsresult CacheProtocolHandler(const char* scheme,
|
||||
nsIProtocolHandler* handler);
|
||||
|
||||
nsresult InitializeCaptivePortalService();
|
||||
nsresult RecheckCaptivePortalIfLocalRedirect(nsIChannel* newChan);
|
||||
|
||||
@ -205,6 +196,9 @@ class nsIOService final : public nsIIOService,
|
||||
|
||||
nsresult SetOfflineInternal(bool offline, bool notifySocketProcess = true);
|
||||
|
||||
bool UsesExternalProtocolHandler(const nsACString& aScheme)
|
||||
MOZ_REQUIRES_SHARED(mLock);
|
||||
|
||||
private:
|
||||
mozilla::Atomic<bool, mozilla::Relaxed> mOffline{true};
|
||||
mozilla::Atomic<bool, mozilla::Relaxed> mOfflineForProfileChange{false};
|
||||
@ -226,15 +220,15 @@ class nsIOService final : public nsIIOService,
|
||||
nsCOMPtr<nsINetworkLinkService> mNetworkLinkService;
|
||||
bool mNetworkLinkServiceInitialized{false};
|
||||
|
||||
// Cached protocol handlers, only accessed on the main thread
|
||||
nsWeakPtr mWeakHandler[NS_N(gScheme)];
|
||||
|
||||
// cached categories
|
||||
nsCategoryCache<nsIChannelEventSink> mChannelEventSinks{
|
||||
NS_CHANNEL_EVENT_SINK_CATEGORY};
|
||||
|
||||
Mutex mMutex{"nsIOService::mMutex"};
|
||||
nsTArray<int32_t> mRestrictedPortList MOZ_GUARDED_BY(mMutex);
|
||||
RWLock mLock{"nsIOService::mLock"};
|
||||
nsTArray<int32_t> mRestrictedPortList MOZ_GUARDED_BY(mLock);
|
||||
nsTArray<nsCString> mForceExternalSchemes MOZ_GUARDED_BY(mLock);
|
||||
nsTHashMap<nsCString, RuntimeProtocolHandler> mRuntimeProtocolHandlers
|
||||
MOZ_GUARDED_BY(mLock);
|
||||
|
||||
uint32_t mTotalRequests{0};
|
||||
uint32_t mCacheWon{0};
|
||||
|
@ -37,6 +37,9 @@ interface nsIProtocolHandlerWithDynamicFlags : nsISupports
|
||||
/*
|
||||
* Returns protocol flags for the given URI, which may be different from the
|
||||
* flags for another URI of the same scheme.
|
||||
*
|
||||
* Only DYNAMIC_URI_FLAGS may be different from the registered flags for the
|
||||
* protocol handler.
|
||||
*/
|
||||
unsigned long getFlagsForURI(in nsIURI aURI);
|
||||
};
|
||||
@ -112,6 +115,10 @@ interface nsIProtocolHandler : nsISupports
|
||||
* Constants for the protocol flags (the first is the default mask, the
|
||||
* others are deviations):
|
||||
*
|
||||
* NOTE: Protocol flags are provided when the protocol handler is
|
||||
* registered, either through a static component or dynamically with
|
||||
* `nsIIOService.registerProtocolHandler`.
|
||||
*
|
||||
* NOTE: Implementation must ignore any flags they do not understand.
|
||||
*/
|
||||
|
||||
@ -331,7 +338,8 @@ interface nsIProtocolHandler : nsISupports
|
||||
* Flags which are allowed to be different from the static flags when
|
||||
* returned from `nsIProtocolHandlerWithDynamicFlags::getFlagsForURI`.
|
||||
*
|
||||
* All other flags must match the `protocolFlags` attribute.
|
||||
* All other flags must match the flags provided when the protocol handler
|
||||
* was registered.
|
||||
*/
|
||||
const unsigned long DYNAMIC_URI_FLAGS =
|
||||
URI_LOADABLE_BY_ANYONE | URI_DANGEROUS_TO_LOAD |
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "mozilla/LoadContext.h"
|
||||
#include "mozilla/LoadInfo.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "mozilla/StaticPrefs_browser.h"
|
||||
#include "mozilla/StaticPrefs_network.h"
|
||||
#include "mozilla/StaticPrefs_privacy.h"
|
||||
#include "mozilla/StoragePrincipalHelper.h"
|
||||
@ -26,6 +27,7 @@
|
||||
#include "nsCategoryCache.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsEscape.h"
|
||||
#include "nsFileStreams.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsHttp.h"
|
||||
@ -666,9 +668,11 @@ int32_t NS_GetDefaultPort(const char* scheme,
|
||||
nsIIOService* ioService /* = nullptr */) {
|
||||
nsresult rv;
|
||||
|
||||
// Getting the default port through the protocol handler has a lot of XPCOM
|
||||
// overhead involved. We optimize the protocols that matter for Web pages
|
||||
// (HTTP and HTTPS) by hardcoding their default ports here.
|
||||
// Getting the default port through the protocol handler previously had a lot
|
||||
// of XPCOM overhead involved. We optimize the protocols that matter for Web
|
||||
// pages (HTTP and HTTPS) by hardcoding their default ports here.
|
||||
//
|
||||
// XXX: This might not be necessary for performance anymore.
|
||||
if (strncmp(scheme, "http", 4) == 0) {
|
||||
if (scheme[4] == 's' && scheme[5] == '\0') {
|
||||
return 443;
|
||||
@ -682,11 +686,8 @@ int32_t NS_GetDefaultPort(const char* scheme,
|
||||
net_EnsureIOService(&ioService, grip);
|
||||
if (!ioService) return -1;
|
||||
|
||||
nsCOMPtr<nsIProtocolHandler> handler;
|
||||
rv = ioService->GetProtocolHandler(scheme, getter_AddRefs(handler));
|
||||
if (NS_FAILED(rv)) return -1;
|
||||
int32_t port;
|
||||
rv = handler->GetDefaultPort(&port);
|
||||
rv = ioService->GetDefaultPort(scheme, &port);
|
||||
return NS_SUCCEEDED(rv) ? port : -1;
|
||||
}
|
||||
|
||||
|
@ -2017,6 +2017,7 @@ void nsProtocolProxyService::LoadHostFilters(const nsACString& aFilters) {
|
||||
|
||||
nsresult nsProtocolProxyService::GetProtocolInfo(nsIURI* uri,
|
||||
nsProtocolInfo* info) {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(uri, "URI is null");
|
||||
MOZ_ASSERT(info, "info is null");
|
||||
|
||||
@ -2028,14 +2029,10 @@ nsresult nsProtocolProxyService::GetProtocolInfo(nsIURI* uri,
|
||||
nsCOMPtr<nsIIOService> ios = do_GetIOService(&rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIProtocolHandler> handler;
|
||||
rv = ios->GetProtocolHandler(info->scheme.get(), getter_AddRefs(handler));
|
||||
rv = ios->GetDynamicProtocolFlags(uri, &info->flags);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = handler->DoGetProtocolFlags(uri, &info->flags);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = handler->GetDefaultPort(&info->defaultPort);
|
||||
rv = ios->GetDefaultPort(info->scheme.get(), &info->defaultPort);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -23,15 +23,6 @@ CustomProtocolHandler.prototype = {
|
||||
get scheme() {
|
||||
return SCHEME;
|
||||
},
|
||||
get defaultPort() {
|
||||
return -1;
|
||||
},
|
||||
get protocolFlags() {
|
||||
return (
|
||||
Ci.nsIProtocolHandler.URI_NORELATIVE |
|
||||
Ci.nsIProtocolHandler.URI_IS_LOCAL_RESOURCE
|
||||
);
|
||||
},
|
||||
newChannel(aURI, aLoadInfo) {
|
||||
return new CustomChannel(aURI, aLoadInfo);
|
||||
},
|
||||
@ -39,14 +30,8 @@ CustomProtocolHandler.prototype = {
|
||||
return port != -1;
|
||||
},
|
||||
|
||||
/** nsIFactory */
|
||||
createInstance(aIID) {
|
||||
return this.QueryInterface(aIID);
|
||||
},
|
||||
|
||||
/** nsISupports */
|
||||
QueryInterface: ChromeUtils.generateQI(["nsIProtocolHandler", "nsIFactory"]),
|
||||
classID: Components.ID("{16d594bc-d9d8-47ae-a139-ea714dc0c35c}"),
|
||||
QueryInterface: ChromeUtils.generateQI(["nsIProtocolHandler"]),
|
||||
};
|
||||
|
||||
function CustomChannel(aURI, aLoadInfo) {
|
||||
@ -250,15 +235,15 @@ function loadTestTab(uri) {
|
||||
|
||||
add_task(async function() {
|
||||
var handler = new CustomProtocolHandler();
|
||||
var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
registrar.registerFactory(
|
||||
handler.classID,
|
||||
"",
|
||||
"@mozilla.org/network/protocol;1?name=" + handler.scheme,
|
||||
handler
|
||||
Services.io.registerProtocolHandler(
|
||||
SCHEME,
|
||||
handler,
|
||||
Ci.nsIProtocolHandler.URI_NORELATIVE |
|
||||
Ci.nsIProtocolHandler.URI_IS_LOCAL_RESOURCE,
|
||||
-1
|
||||
);
|
||||
registerCleanupFunction(function() {
|
||||
registrar.unregisterFactory(handler.classID, handler);
|
||||
Services.io.unregisterProtocolHandler(SCHEME);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -21,19 +21,6 @@ ProtocolHandler.prototype = {
|
||||
get scheme() {
|
||||
return "x-bug894586";
|
||||
},
|
||||
get defaultPort() {
|
||||
return -1;
|
||||
},
|
||||
get protocolFlags() {
|
||||
return (
|
||||
Ci.nsIProtocolHandler.URI_NORELATIVE |
|
||||
Ci.nsIProtocolHandler.URI_NOAUTH |
|
||||
Ci.nsIProtocolHandler.URI_IS_UI_RESOURCE |
|
||||
Ci.nsIProtocolHandler.URI_IS_LOCAL_RESOURCE |
|
||||
Ci.nsIProtocolHandler.URI_NON_PERSISTABLE |
|
||||
Ci.nsIProtocolHandler.URI_SYNC_LOAD_IS_OK
|
||||
);
|
||||
},
|
||||
newChannel(aURI, aLoadInfo) {
|
||||
this.loadInfo = aLoadInfo;
|
||||
return this;
|
||||
@ -106,19 +93,12 @@ ProtocolHandler.prototype = {
|
||||
Ci.nsIRequest.INHIBIT_CACHING |
|
||||
Ci.nsIRequest.LOAD_BYPASS_CACHE,
|
||||
|
||||
/** nsIFactory */
|
||||
createInstance(aIID) {
|
||||
return this.QueryInterface(aIID);
|
||||
},
|
||||
|
||||
/** nsISupports */
|
||||
QueryInterface: ChromeUtils.generateQI([
|
||||
"nsIProtocolHandler",
|
||||
"nsIRequest",
|
||||
"nsIChannel",
|
||||
"nsIFactory",
|
||||
]),
|
||||
classID: Components.ID("{16d594bc-d9d8-47ae-a139-ea714dc0c35c}"),
|
||||
};
|
||||
|
||||
/**
|
||||
@ -127,12 +107,17 @@ ProtocolHandler.prototype = {
|
||||
*/
|
||||
function run_test() {
|
||||
var handler = new ProtocolHandler();
|
||||
var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
|
||||
registrar.registerFactory(
|
||||
handler.classID,
|
||||
"",
|
||||
"@mozilla.org/network/protocol;1?name=" + handler.scheme,
|
||||
handler
|
||||
|
||||
Services.io.registerProtocolHandler(
|
||||
handler.scheme,
|
||||
handler,
|
||||
Ci.nsIProtocolHandler.URI_NORELATIVE |
|
||||
Ci.nsIProtocolHandler.URI_NOAUTH |
|
||||
Ci.nsIProtocolHandler.URI_IS_UI_RESOURCE |
|
||||
Ci.nsIProtocolHandler.URI_IS_LOCAL_RESOURCE |
|
||||
Ci.nsIProtocolHandler.URI_NON_PERSISTABLE |
|
||||
Ci.nsIProtocolHandler.URI_SYNC_LOAD_IS_OK,
|
||||
-1
|
||||
);
|
||||
try {
|
||||
var ss = Cc["@mozilla.org/content/style-sheet-service;1"].getService(
|
||||
@ -143,7 +128,7 @@ function run_test() {
|
||||
ss.sheetRegistered(handler.uri, Ci.nsIStyleSheetService.AGENT_SHEET)
|
||||
);
|
||||
} finally {
|
||||
registrar.unregisterFactory(handler.classID, handler);
|
||||
Services.io.unregisterProtocolHandler(handler.scheme);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -249,7 +249,7 @@ export class Proxy {
|
||||
if (scheme === "socks") {
|
||||
port = null;
|
||||
} else {
|
||||
port = Services.io.getProtocolHandler(scheme).defaultPort;
|
||||
port = Services.io.getDefaultPort(scheme);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,7 +66,6 @@ const backgroundtaskPhases = {
|
||||
"@mozilla.org/network/idn-service;1",
|
||||
"@mozilla.org/network/io-service;1",
|
||||
"@mozilla.org/network/network-link-service;1",
|
||||
"@mozilla.org/network/protocol;1?name=chrome",
|
||||
"@mozilla.org/network/protocol;1?name=file",
|
||||
"@mozilla.org/network/protocol;1?name=jar",
|
||||
"@mozilla.org/network/protocol;1?name=resource",
|
||||
|
@ -290,22 +290,10 @@ bool DownloadPlatform::IsURLPossiblyFromWeb(nsIURI* aURI) {
|
||||
}
|
||||
|
||||
while (uri) {
|
||||
// We're not using nsIIOService::ProtocolHasFlags because it doesn't
|
||||
// take per-URI flags into account. We're also not using
|
||||
// NS_URIChainHasFlags because we're checking for *any* of 3 flags
|
||||
// to be present on *all* of the nested URIs, which it can't do.
|
||||
nsAutoCString scheme;
|
||||
nsresult rv = uri->GetScheme(scheme);
|
||||
if (NS_FAILED(rv)) {
|
||||
return true;
|
||||
}
|
||||
nsCOMPtr<nsIProtocolHandler> ph;
|
||||
rv = ios->GetProtocolHandler(scheme.get(), getter_AddRefs(ph));
|
||||
if (NS_FAILED(rv)) {
|
||||
return true;
|
||||
}
|
||||
// We're not using NS_URIChainHasFlags because we're checking for *any* of 3
|
||||
// flags to be present on *all* of the nested URIs, which it can't do.
|
||||
uint32_t flags;
|
||||
rv = ph->DoGetProtocolFlags(uri, &flags);
|
||||
nsresult rv = ios->GetDynamicProtocolFlags(uri, &flags);
|
||||
if (NS_FAILED(rv)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ class MatchURLFilters {
|
||||
if (["resource", "chrome"].includes(uri.scheme)) {
|
||||
port = undefined;
|
||||
} else {
|
||||
port = Services.io.getProtocolHandler(uri.scheme).defaultPort;
|
||||
port = Services.io.getDefaultPort(uri.scheme);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user