Skip to content

Commit

Permalink
Bug 1532253 - Add NS_NewURIOnAnyThread r=baku
Browse files Browse the repository at this point in the history
Differential Revision: https://phabricator.services.mozilla.com/D22137

--HG--
extra : moz-landing-system : lando
  • Loading branch information
valenting committed Mar 19, 2019
1 parent e7c069f commit 87e9bbf
Show file tree
Hide file tree
Showing 15 changed files with 243 additions and 15 deletions.
4 changes: 4 additions & 0 deletions chrome/moz.build
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ XPIDL_SOURCES += [

XPIDL_MODULE = 'chrome'

EXPORTS += [
'nsChromeProtocolHandler.h',
]

EXPORTS.mozilla.chrome += [
'RegistryMessageUtils.h',
]
Expand Down
7 changes: 7 additions & 0 deletions chrome/nsChromeProtocolHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions chrome/nsChromeProtocolHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -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() {}
Expand Down
26 changes: 16 additions & 10 deletions dom/jsurl/nsJSProtocolHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -1042,20 +1043,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)) {
Expand Down Expand Up @@ -1090,10 +1090,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
Expand Down
10 changes: 5 additions & 5 deletions dom/jsurl/nsJSProtocolHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

#include "mozilla/Attributes.h"
#include "nsIProtocolHandler.h"
#include "nsITextToSubURI.h"
#include "nsIURI.h"
#include "nsIMutable.h"
#include "nsISerializable.h"
Expand Down Expand Up @@ -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 {
Expand Down
2 changes: 2 additions & 0 deletions mfbt/ThreadLocal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
126 changes: 126 additions & 0 deletions netwerk/base/nsNetUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand Down Expand Up @@ -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<decltype(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();
Expand Down
13 changes: 13 additions & 0 deletions netwerk/base/nsNetUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,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 =
Expand Down
4 changes: 4 additions & 0 deletions netwerk/protocol/data/moz.build
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ EXPORTS.mozilla.net += [
'DataChannelParent.h',
]

EXPORTS += [
'nsDataHandler.h',
]

UNIFIED_SOURCES += [
'DataChannelChild.cpp',
'DataChannelParent.cpp',
Expand Down
7 changes: 7 additions & 0 deletions netwerk/protocol/data/nsDataHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
3 changes: 3 additions & 0 deletions netwerk/protocol/data/nsDataHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
38 changes: 38 additions & 0 deletions netwerk/test/gtest/TestURIMutator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include "nsNetCID.h"
#include "nsIURL.h"
#include "nsIURIMutator.h"
#include "nsThreadPool.h"
#include "nsNetUtil.h"

TEST(TestURIMutator, Mutator) {
nsAutoCString out;
Expand Down Expand Up @@ -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);
}
14 changes: 14 additions & 0 deletions xpcom/threads/ThreadLocalVariables.cpp
Original file line number Diff line number Diff line change
@@ -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);
}
1 change: 1 addition & 0 deletions xpcom/threads/moz.build
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ UNIFIED_SOURCES += [
'TaskQueue.cpp',
'ThreadEventQueue.cpp',
'ThreadEventTarget.cpp',
'ThreadLocalVariables.cpp',
'ThrottledEventQueue.cpp',
'TimerThread.cpp',
]
Expand Down
1 change: 1 addition & 0 deletions xpcom/threads/nsThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,7 @@ void nsThread::InitCommon() {
#endif
}

InitThreadLocalVariables();
AddToThreadList();
}

Expand Down

0 comments on commit 87e9bbf

Please sign in to comment.