зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1532253 - Add NS_NewURIOnAnyThread r=baku!
Differential Revision: https://phabricator.services.mozilla.com/D22137 --HG-- extra : source : d33b895e5ebeef0ade779ad35323d698f710a5a5 extra : intermediate-source : 82c14f26f6de19645d4e0f4a5f4d44eaa99536f3
This commit is contained in:
Родитель
fe0717fb48
Коммит
815b481df4
|
@ -13,6 +13,10 @@ XPIDL_SOURCES += [
|
|||
|
||||
XPIDL_MODULE = 'chrome'
|
||||
|
||||
EXPORTS += [
|
||||
'nsChromeProtocolHandler.h',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla.chrome += [
|
||||
'RegistryMessageUtils.h',
|
||||
]
|
||||
|
|
|
@ -66,6 +66,13 @@ nsChromeProtocolHandler::GetProtocolFlags(uint32_t *result) {
|
|||
NS_IMETHODIMP
|
||||
nsChromeProtocolHandler::NewURI(const nsACString &aSpec, const char *aCharset,
|
||||
nsIURI *aBaseURI, nsIURI **result) {
|
||||
return nsChromeProtocolHandler::CreateNewURI(aSpec, aCharset, aBaseURI,
|
||||
result);
|
||||
}
|
||||
|
||||
/* static */ nsresult nsChromeProtocolHandler::CreateNewURI(
|
||||
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;
|
||||
|
|
|
@ -27,6 +27,8 @@ class nsChromeProtocolHandler final : public nsIProtocolHandler,
|
|||
|
||||
// nsChromeProtocolHandler methods:
|
||||
nsChromeProtocolHandler() {}
|
||||
static nsresult CreateNewURI(const nsACString &aSpec, const char *aCharset,
|
||||
nsIURI *aBaseURI, nsIURI **result);
|
||||
|
||||
private:
|
||||
~nsChromeProtocolHandler() {}
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "nsILoadInfo.h"
|
||||
#include "nsIObjectInputStream.h"
|
||||
#include "nsIObjectOutputStream.h"
|
||||
#include "nsITextToSubURI.h"
|
||||
#include "nsIWritablePropertyBag2.h"
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
#include "nsSandboxFlags.h"
|
||||
|
@ -1044,20 +1045,19 @@ nsresult nsJSProtocolHandler::Create(nsISupports* aOuter, REFNSIID aIID,
|
|||
return rv;
|
||||
}
|
||||
|
||||
nsresult nsJSProtocolHandler::EnsureUTF8Spec(const nsCString& aSpec,
|
||||
const char* aCharset,
|
||||
nsACString& aUTF8Spec) {
|
||||
/* static */ nsresult nsJSProtocolHandler::EnsureUTF8Spec(
|
||||
const nsCString& aSpec, const char* aCharset, nsACString& aUTF8Spec) {
|
||||
aUTF8Spec.Truncate();
|
||||
|
||||
nsresult rv;
|
||||
|
||||
if (!mTextToSubURI) {
|
||||
mTextToSubURI = do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
nsCOMPtr<nsITextToSubURI> txtToSubURI =
|
||||
do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoString uStr;
|
||||
rv = mTextToSubURI->UnEscapeNonAsciiURI(nsDependentCString(aCharset), aSpec,
|
||||
uStr);
|
||||
rv = txtToSubURI->UnEscapeNonAsciiURI(nsDependentCString(aCharset), aSpec,
|
||||
uStr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!IsASCII(uStr)) {
|
||||
|
@ -1092,10 +1092,16 @@ nsJSProtocolHandler::GetProtocolFlags(uint32_t* result) {
|
|||
URI_OPENING_EXECUTES_SCRIPT;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsJSProtocolHandler::NewURI(const nsACString& aSpec, const char* aCharset,
|
||||
nsIURI* aBaseURI, nsIURI** result) {
|
||||
return nsJSProtocolHandler::CreateNewURI(aSpec, aCharset, aBaseURI, result);
|
||||
}
|
||||
|
||||
/* static */ nsresult nsJSProtocolHandler::CreateNewURI(const nsACString& aSpec,
|
||||
const char* aCharset,
|
||||
nsIURI* aBaseURI,
|
||||
nsIURI** result) {
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// javascript: URLs (currently) have no additional structure beyond that
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsIProtocolHandler.h"
|
||||
#include "nsITextToSubURI.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIMutable.h"
|
||||
#include "nsISerializable.h"
|
||||
|
@ -54,13 +53,14 @@ class nsJSProtocolHandler : public nsIProtocolHandler {
|
|||
|
||||
nsresult Init();
|
||||
|
||||
static nsresult CreateNewURI(const nsACString& aSpec, const char* aCharset,
|
||||
nsIURI* aBaseURI, nsIURI** result);
|
||||
|
||||
protected:
|
||||
virtual ~nsJSProtocolHandler();
|
||||
|
||||
nsresult EnsureUTF8Spec(const nsCString& aSpec, const char* aCharset,
|
||||
nsACString& aUTF8Spec);
|
||||
|
||||
nsCOMPtr<nsITextToSubURI> mTextToSubURI;
|
||||
static nsresult EnsureUTF8Spec(const nsCString& aSpec, const char* aCharset,
|
||||
nsACString& aUTF8Spec);
|
||||
};
|
||||
|
||||
class nsJSURI final : public mozilla::net::nsSimpleURI {
|
||||
|
|
|
@ -178,6 +178,8 @@ class ThreadLocal : public Storage<T> {
|
|||
inline T get() const;
|
||||
|
||||
inline void set(const T aValue);
|
||||
|
||||
using Type = T;
|
||||
};
|
||||
|
||||
template <typename T, template <typename U> class Storage>
|
||||
|
|
|
@ -85,6 +85,10 @@
|
|||
#include "nsQueryObject.h"
|
||||
#include "mozIThirdPartyUtil.h"
|
||||
#include "../mime/nsMIMEHeaderParamImpl.h"
|
||||
#include "nsStandardURL.h"
|
||||
#include "nsChromeProtocolHandler.h"
|
||||
#include "nsJSProtocolHandler.h"
|
||||
#include "nsDataHandler.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
|
@ -1674,6 +1678,128 @@ nsresult NS_NewURI(
|
|||
ioService);
|
||||
}
|
||||
|
||||
static nsresult NewStandardURI(const nsACString &aSpec, const char *aCharset,
|
||||
nsIURI *aBaseURI, int32_t aDefaultPort,
|
||||
nsIURI **aURI) {
|
||||
nsCOMPtr<nsIURI> base(aBaseURI);
|
||||
return NS_MutateURI(new nsStandardURL::Mutator())
|
||||
.Apply(NS_MutatorMethod(&nsIStandardURLMutator::Init,
|
||||
nsIStandardURL::URLTYPE_AUTHORITY, aDefaultPort,
|
||||
nsCString(aSpec), aCharset, base, nullptr))
|
||||
.Finalize(aURI);
|
||||
}
|
||||
|
||||
extern MOZ_THREAD_LOCAL(uint32_t) gTlsURLRecursionCount;
|
||||
|
||||
template <typename T>
|
||||
class TlsAutoIncrement {
|
||||
public:
|
||||
explicit TlsAutoIncrement(T &var) : mVar(var) {
|
||||
mValue = mVar.get();
|
||||
mVar.set(mValue + 1);
|
||||
}
|
||||
~TlsAutoIncrement() {
|
||||
typename T::Type value = mVar.get();
|
||||
MOZ_ASSERT(value == mValue + 1);
|
||||
mVar.set(value - 1);
|
||||
}
|
||||
|
||||
typename T::Type value() { return mValue; }
|
||||
|
||||
private:
|
||||
typename T::Type mValue;
|
||||
T &mVar;
|
||||
};
|
||||
|
||||
nsresult NS_NewURIOnAnyThread(nsIURI **aURI, const nsACString &aSpec,
|
||||
const char *aCharset /* = nullptr */,
|
||||
nsIURI *aBaseURI /* = nullptr */,
|
||||
nsIIOService *aIOService /* = nullptr */) {
|
||||
TlsAutoIncrement<typeof(gTlsURLRecursionCount)> inc(gTlsURLRecursionCount);
|
||||
if (inc.value() >= MAX_RECURSION_COUNT) {
|
||||
return NS_ERROR_MALFORMED_URI;
|
||||
}
|
||||
|
||||
nsAutoCString scheme;
|
||||
nsresult rv = net_ExtractURLScheme(aSpec, scheme);
|
||||
if (NS_FAILED(rv)) {
|
||||
// then aSpec is relative
|
||||
if (!aBaseURI) {
|
||||
return NS_ERROR_MALFORMED_URI;
|
||||
}
|
||||
|
||||
if (!aSpec.IsEmpty() && aSpec[0] == '#') {
|
||||
// Looks like a reference instead of a fully-specified URI.
|
||||
// --> initialize |uri| as a clone of |aBaseURI|, with ref appended.
|
||||
return NS_GetURIWithNewRef(aBaseURI, aSpec, aURI);
|
||||
}
|
||||
|
||||
rv = aBaseURI->GetScheme(scheme);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
if (scheme.EqualsLiteral("http") || scheme.EqualsLiteral("ws")) {
|
||||
return NewStandardURI(aSpec, aCharset, aBaseURI, NS_HTTP_DEFAULT_PORT,
|
||||
aURI);
|
||||
}
|
||||
if (scheme.EqualsLiteral("https") || scheme.EqualsLiteral("wss")) {
|
||||
return NewStandardURI(aSpec, aCharset, aBaseURI, NS_HTTPS_DEFAULT_PORT,
|
||||
aURI);
|
||||
}
|
||||
if (scheme.EqualsLiteral("ftp")) {
|
||||
return NewStandardURI(aSpec, aCharset, aBaseURI, 21, aURI);
|
||||
}
|
||||
|
||||
if (scheme.EqualsLiteral("file")) {
|
||||
nsAutoCString buf(aSpec);
|
||||
#if defined(XP_WIN)
|
||||
buf.Truncate();
|
||||
if (!net_NormalizeFileURL(aSpec, buf)) {
|
||||
buf = aSpec;
|
||||
}
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIURI> base(aBaseURI);
|
||||
return NS_MutateURI(new nsStandardURL::Mutator())
|
||||
.Apply(NS_MutatorMethod(&nsIFileURLMutator::MarkFileURL))
|
||||
.Apply(NS_MutatorMethod(&nsIStandardURLMutator::Init,
|
||||
nsIStandardURL::URLTYPE_NO_AUTHORITY, -1, buf,
|
||||
aCharset, base, nullptr))
|
||||
.Finalize(aURI);
|
||||
}
|
||||
|
||||
if (scheme.EqualsLiteral("data")) {
|
||||
return nsDataHandler::CreateNewURI(aSpec, aCharset, aBaseURI, aURI);
|
||||
}
|
||||
|
||||
if (scheme.EqualsLiteral("moz-safe-about") ||
|
||||
scheme.EqualsLiteral("page-icon") || scheme.EqualsLiteral("moz") ||
|
||||
scheme.EqualsLiteral("moz-anno") ||
|
||||
scheme.EqualsLiteral("moz-page-thumb") ||
|
||||
scheme.EqualsLiteral("moz-fonttable")) {
|
||||
return NS_MutateURI(new nsSimpleURI::Mutator())
|
||||
.SetSpec(aSpec)
|
||||
.Finalize(aURI);
|
||||
}
|
||||
|
||||
if (scheme.EqualsLiteral("chrome")) {
|
||||
return nsChromeProtocolHandler::CreateNewURI(aSpec, aCharset, aBaseURI,
|
||||
aURI);
|
||||
}
|
||||
|
||||
if (scheme.EqualsLiteral("javascript")) {
|
||||
return nsJSProtocolHandler::CreateNewURI(aSpec, aCharset, aBaseURI, aURI);
|
||||
}
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
// XXX (valentin): this fallback should be removed once we get rid of
|
||||
// nsIProtocolHandler.newURI
|
||||
return NS_NewURI(aURI, aSpec, aCharset, aBaseURI, aIOService);
|
||||
}
|
||||
|
||||
return NS_ERROR_UNKNOWN_PROTOCOL;
|
||||
}
|
||||
|
||||
nsresult NS_GetSanitizedURIStringFromURI(nsIURI *aUri,
|
||||
nsAString &aSanitizedSpec) {
|
||||
aSanitizedSpec.Truncate();
|
||||
|
|
|
@ -100,6 +100,19 @@ nsresult NS_NewURI(nsIURI **result, const char *spec, nsIURI *baseURI = nullptr,
|
|||
nsIIOService *ioService =
|
||||
nullptr); // pass in nsIIOService to optimize callers
|
||||
|
||||
// This function attempts to create an nsIURI on any thread. This implies we
|
||||
// can't instantiate a protcol handler, since protocol handers may have a JS
|
||||
// implementation so they can't work off-main-thread.
|
||||
// When called off the main thread, if the nsIURI can't be created without
|
||||
// instantiating protocol handlers, the method will return
|
||||
// NS_ERROR_UNKNOWN_PROTOCOL. The caller may retry on the main thread.
|
||||
// When called on the main thread, this function will fall back on calling
|
||||
// nsIProtocolHandler.newURI
|
||||
nsresult NS_NewURIOnAnyThread(nsIURI **aResult, const nsACString &aSpec,
|
||||
const char *aCharset = nullptr,
|
||||
nsIURI *aBaseURI = nullptr,
|
||||
nsIIOService *aIOService = nullptr);
|
||||
|
||||
nsresult NS_NewFileURI(
|
||||
nsIURI **result, nsIFile *spec,
|
||||
nsIIOService *ioService =
|
||||
|
|
|
@ -8,6 +8,10 @@ EXPORTS.mozilla.net += [
|
|||
'DataChannelParent.h',
|
||||
]
|
||||
|
||||
EXPORTS += [
|
||||
'nsDataHandler.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'DataChannelChild.cpp',
|
||||
'DataChannelParent.cpp',
|
||||
|
|
|
@ -51,6 +51,13 @@ NS_IMETHODIMP
|
|||
nsDataHandler::NewURI(const nsACString& aSpec,
|
||||
const char* aCharset, // ignore charset info
|
||||
nsIURI* aBaseURI, nsIURI** result) {
|
||||
return nsDataHandler::CreateNewURI(aSpec, aCharset, aBaseURI, result);
|
||||
}
|
||||
|
||||
/* static */ nsresult nsDataHandler::CreateNewURI(const nsACString& aSpec,
|
||||
const char* aCharset,
|
||||
nsIURI* aBaseURI,
|
||||
nsIURI** result) {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
|
||||
|
|
|
@ -22,6 +22,9 @@ class nsDataHandler : public nsIProtocolHandler,
|
|||
// nsDataHandler methods:
|
||||
nsDataHandler() = default;
|
||||
|
||||
static nsresult CreateNewURI(const nsACString& aSpec, const char* aCharset,
|
||||
nsIURI* aBaseURI, nsIURI** result);
|
||||
|
||||
// Define a Create method to be used with a factory:
|
||||
static MOZ_MUST_USE nsresult Create(nsISupports* aOuter, const nsIID& aIID,
|
||||
void** aResult);
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
#include "nsNetCID.h"
|
||||
#include "nsIURL.h"
|
||||
#include "nsIURIMutator.h"
|
||||
#include "nsThreadPool.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
TEST(TestURIMutator, Mutator) {
|
||||
nsAutoCString out;
|
||||
|
@ -97,3 +99,39 @@ TEST(TestURIMutator, Mutator) {
|
|||
ASSERT_EQ(rv, NS_ERROR_NOT_AVAILABLE);
|
||||
ASSERT_TRUE(uri3 == nullptr);
|
||||
}
|
||||
|
||||
extern MOZ_THREAD_LOCAL(uint32_t) gTlsURLRecursionCount;
|
||||
|
||||
TEST(TestURIMutator, NS_NewURIOnAnyThread) {
|
||||
nsCOMPtr<nsIThreadPool> pool = new nsThreadPool();
|
||||
pool->SetThreadLimit(60);
|
||||
|
||||
pool = new nsThreadPool();
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
nsCOMPtr<nsIRunnable> task =
|
||||
NS_NewRunnableFunction("gtest-NS_NewURIOnAnyThread", []() {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = NS_NewURIOnAnyThread(
|
||||
getter_AddRefs(uri), NS_LITERAL_CSTRING("http://example.com"));
|
||||
ASSERT_EQ(rv, NS_OK);
|
||||
nsAutoCString out;
|
||||
ASSERT_EQ(uri->GetSpec(out), NS_OK);
|
||||
ASSERT_TRUE(out == NS_LITERAL_CSTRING("http://example.com/"));
|
||||
});
|
||||
EXPECT_TRUE(task);
|
||||
|
||||
pool->Dispatch(task, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = NS_NewURIOnAnyThread(getter_AddRefs(uri),
|
||||
NS_LITERAL_CSTRING("http://example.com"));
|
||||
ASSERT_EQ(rv, NS_OK);
|
||||
nsAutoCString out;
|
||||
ASSERT_EQ(uri->GetSpec(out), NS_OK);
|
||||
ASSERT_TRUE(out == NS_LITERAL_CSTRING("http://example.com/"));
|
||||
|
||||
pool->Shutdown();
|
||||
|
||||
ASSERT_EQ(gTlsURLRecursionCount.get(), 0u);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
/* 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/. */
|
||||
|
||||
// This variable is used to ensure creating new URI doesn't put us in an
|
||||
// infinite loop
|
||||
MOZ_THREAD_LOCAL(uint32_t) gTlsURLRecursionCount;
|
||||
|
||||
void InitThreadLocalVariables() {
|
||||
if (!gTlsURLRecursionCount.init()) {
|
||||
MOZ_CRASH("Could not init gTlsURLRecursionCount");
|
||||
}
|
||||
gTlsURLRecursionCount.set(0);
|
||||
}
|
|
@ -107,6 +107,7 @@ UNIFIED_SOURCES += [
|
|||
'TaskQueue.cpp',
|
||||
'ThreadEventQueue.cpp',
|
||||
'ThreadEventTarget.cpp',
|
||||
'ThreadLocalVariables.cpp',
|
||||
'ThrottledEventQueue.cpp',
|
||||
'TimerThread.cpp',
|
||||
]
|
||||
|
|
|
@ -572,6 +572,7 @@ void nsThread::InitCommon() {
|
|||
#endif
|
||||
}
|
||||
|
||||
InitThreadLocalVariables();
|
||||
AddToThreadList();
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче