Bug 1561860 - Add rust-url based nsIURI implementation r=JuniorHsu

This patch adds DefaultURI which wraps MozURL which in turn forwards calls
to rust-url.
For the moment the added network.url.useDefaultURI is set to false by default.
The plan is to make this the default implementation for unknown URI types.

Differential Revision: https://phabricator.services.mozilla.com/D54748

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Valentin Gosu 2019-12-11 20:17:53 +00:00
parent 2f3a3b594c
commit 99cfec8178
13 changed files with 869 additions and 6 deletions

View File

@ -18,6 +18,11 @@ struct SimpleURIParams
nsCString query;
};
struct DefaultURIParams
{
nsCString spec;
};
struct StandardURLSegment
{
uint32_t position;
@ -85,6 +90,7 @@ union URIParams
JSURIParams;
SimpleNestedURIParams;
HostObjectURIParams;
DefaultURIParams;
};
struct JSURIParams

View File

@ -9,6 +9,7 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/Assertions.h"
#include "mozilla/dom/BlobURL.h"
#include "mozilla/net/DefaultURI.h"
#include "mozilla/net/SubstitutingURL.h"
#include "mozilla/NullPrincipalURI.h"
#include "nsComponentManagerUtils.h"
@ -101,6 +102,10 @@ already_AddRefed<nsIURI> DeserializeURI(const URIParams& aParams) {
mutator = new mozilla::dom::BlobURL::Mutator();
break;
case URIParams::TDefaultURIParams:
mutator = new mozilla::net::DefaultURI::Mutator();
break;
default:
MOZ_CRASH("Unknown params!");
}

View File

@ -7006,6 +7006,11 @@
value: true
mirror: always
# Whether to use the rust implemented DefaultURI for unknown scheme types
- name: network.url.useDefaultURI
type: RelaxedAtomicBool
value: false
mirror: always
#---------------------------------------------------------------------------
# Prefs starting with "nglayout."

560
netwerk/base/DefaultURI.cpp Normal file
View File

@ -0,0 +1,560 @@
/* 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 "DefaultURI.h"
#include "nsIObjectInputStream.h"
#include "nsIObjectOutputStream.h"
namespace mozilla {
namespace net {
#define NS_DEFAULTURI_CID \
{ /* 04445aa0-fd27-4c99-bd41-6be6318ae92c */ \
0x04445aa0, 0xfd27, 0x4c99, { \
0xbd, 0x41, 0x6b, 0xe6, 0x31, 0x8a, 0xe9, 0x2c \
} \
}
#define ASSIGN_AND_ADDREF_THIS(ptrToMutator) \
do { \
if (ptrToMutator) { \
NS_ADDREF(*ptrToMutator = this); \
} \
} while (0)
static NS_DEFINE_CID(kDefaultURICID, NS_DEFAULTURI_CID);
NS_IMPL_ADDREF(DefaultURI)
NS_IMPL_RELEASE(DefaultURI)
NS_INTERFACE_TABLE_HEAD(DefaultURI)
NS_INTERFACE_TABLE(DefaultURI, nsIURI, nsISerializable, nsIClassInfo)
NS_INTERFACE_TABLE_TO_MAP_SEGUE
if (aIID.Equals(kDefaultURICID))
foundInterface = static_cast<nsIURI*>(this);
else
NS_INTERFACE_MAP_ENTRY(nsISizeOf)
NS_INTERFACE_MAP_END
//----------------------------------------------------------------------------
// nsISerializable
//----------------------------------------------------------------------------
NS_IMETHODIMP DefaultURI::Read(nsIObjectInputStream* aInputStream) {
MOZ_ASSERT_UNREACHABLE("Use nsIURIMutator.read() instead");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP DefaultURI::Write(nsIObjectOutputStream* aOutputStream) {
nsAutoCString spec(mURL->Spec());
return aOutputStream->WriteStringZ(spec.get());
}
//----------------------------------------------------------------------------
// nsIClassInfo
//----------------------------------------------------------------------------
NS_IMETHODIMP DefaultURI::GetInterfaces(nsTArray<nsIID>& aInterfaces) {
aInterfaces.Clear();
return NS_OK;
}
NS_IMETHODIMP DefaultURI::GetScriptableHelper(nsIXPCScriptable** _retval) {
*_retval = nullptr;
return NS_OK;
}
NS_IMETHODIMP DefaultURI::GetContractID(nsACString& aContractID) {
aContractID.SetIsVoid(true);
return NS_OK;
}
NS_IMETHODIMP DefaultURI::GetClassDescription(nsACString& aClassDescription) {
aClassDescription.SetIsVoid(true);
return NS_OK;
}
NS_IMETHODIMP DefaultURI::GetClassID(nsCID** aClassID) {
*aClassID = (nsCID*)moz_xmalloc(sizeof(nsCID));
return GetClassIDNoAlloc(*aClassID);
}
NS_IMETHODIMP DefaultURI::GetFlags(uint32_t* aFlags) {
*aFlags = nsIClassInfo::MAIN_THREAD_ONLY;
return NS_OK;
}
NS_IMETHODIMP DefaultURI::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) {
*aClassIDNoAlloc = kDefaultURICID;
return NS_OK;
}
//----------------------------------------------------------------------------
// nsISizeOf
//----------------------------------------------------------------------------
size_t DefaultURI::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
return mURL->SizeOf();
}
size_t DefaultURI::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
}
//----------------------------------------------------------------------------
// nsIURI
//----------------------------------------------------------------------------
NS_IMETHODIMP DefaultURI::GetSpec(nsACString& aSpec) {
aSpec = mURL->Spec();
return NS_OK;
}
NS_IMETHODIMP DefaultURI::GetPrePath(nsACString& aPrePath) {
aPrePath = mURL->PrePath();
return NS_OK;
}
NS_IMETHODIMP DefaultURI::GetScheme(nsACString& aScheme) {
aScheme = mURL->Scheme();
return NS_OK;
}
NS_IMETHODIMP DefaultURI::GetUserPass(nsACString& aUserPass) {
aUserPass = mURL->Username();
nsAutoCString pass(mURL->Password());
if (pass.IsEmpty()) {
return NS_OK;
}
aUserPass.Append(':');
aUserPass.Append(pass);
return NS_OK;
}
NS_IMETHODIMP DefaultURI::GetUsername(nsACString& aUsername) {
aUsername = mURL->Username();
return NS_OK;
}
NS_IMETHODIMP DefaultURI::GetPassword(nsACString& aPassword) {
aPassword = mURL->Password();
return NS_OK;
}
NS_IMETHODIMP DefaultURI::GetHostPort(nsACString& aHostPort) {
aHostPort = mURL->HostPort();
return NS_OK;
}
NS_IMETHODIMP DefaultURI::GetHost(nsACString& aHost) {
aHost = mURL->Host();
// Historically nsIURI.host has always returned an IPv6 address that isn't
// enclosed in brackets. Ideally we want to change that, but for the sake of
// consitency we'll leave it like that for the moment.
// Bug 1603199 should fix this.
if (StringBeginsWith(aHost, NS_LITERAL_CSTRING("[")) &&
StringEndsWith(aHost, NS_LITERAL_CSTRING("]")) &&
aHost.FindChar(':') != kNotFound) {
aHost = Substring(aHost, 1, aHost.Length() - 2);
}
return NS_OK;
}
NS_IMETHODIMP DefaultURI::GetPort(int32_t* aPort) {
*aPort = mURL->Port();
return NS_OK;
}
NS_IMETHODIMP DefaultURI::GetPathQueryRef(nsACString& aPathQueryRef) {
aPathQueryRef = mURL->Path();
return NS_OK;
}
NS_IMETHODIMP DefaultURI::Equals(nsIURI* other, bool* _retval) {
RefPtr<DefaultURI> otherUri;
nsresult rv = other->QueryInterface(kDefaultURICID, getter_AddRefs(otherUri));
if (NS_FAILED(rv)) {
*_retval = false;
return NS_OK;
}
*_retval = mURL->Spec() == otherUri->mURL->Spec();
return NS_OK;
}
NS_IMETHODIMP DefaultURI::SchemeIs(const char* scheme, bool* _retval) {
*_retval = mURL->Scheme().Equals(scheme);
return NS_OK;
}
NS_IMETHODIMP DefaultURI::Resolve(const nsACString& aRelativePath,
nsACString& aResult) {
nsAutoCString scheme;
nsresult rv = net_ExtractURLScheme(aRelativePath, scheme);
if (NS_SUCCEEDED(rv)) {
aResult = aRelativePath;
return NS_OK;
}
// We try to create another URL with this one as its base.
RefPtr<MozURL> resolvedURL;
rv = MozURL::Init(getter_AddRefs(resolvedURL), aRelativePath, mURL);
if (NS_WARN_IF(NS_FAILED(rv))) {
// If parsing the relative url fails, we revert to the previous behaviour
// and just return the relative path.
aResult = aRelativePath;
return NS_OK;
}
aResult = resolvedURL->Spec();
return NS_OK;
}
NS_IMETHODIMP DefaultURI::GetAsciiSpec(nsACString& aAsciiSpec) {
return GetSpec(aAsciiSpec);
}
NS_IMETHODIMP DefaultURI::GetAsciiHostPort(nsACString& aAsciiHostPort) {
return GetHostPort(aAsciiHostPort);
}
NS_IMETHODIMP DefaultURI::GetAsciiHost(nsACString& aAsciiHost) {
return GetHost(aAsciiHost);
}
NS_IMETHODIMP DefaultURI::GetRef(nsACString& aRef) {
aRef = mURL->Ref();
return NS_OK;
}
NS_IMETHODIMP DefaultURI::EqualsExceptRef(nsIURI* other, bool* _retval) {
RefPtr<DefaultURI> otherUri;
nsresult rv = other->QueryInterface(kDefaultURICID, getter_AddRefs(otherUri));
if (NS_FAILED(rv)) {
*_retval = false;
return NS_OK;
}
*_retval = mURL->SpecNoRef().Equals(otherUri->mURL->SpecNoRef());
return NS_OK;
}
NS_IMETHODIMP DefaultURI::GetSpecIgnoringRef(nsACString& aSpecIgnoringRef) {
aSpecIgnoringRef = mURL->SpecNoRef();
return NS_OK;
}
NS_IMETHODIMP DefaultURI::GetHasRef(bool* aHasRef) {
*aHasRef = mURL->HasFragment();
return NS_OK;
}
NS_IMETHODIMP DefaultURI::GetFilePath(nsACString& aFilePath) {
aFilePath = mURL->FilePath();
return NS_OK;
}
NS_IMETHODIMP DefaultURI::GetQuery(nsACString& aQuery) {
aQuery = mURL->Query();
return NS_OK;
}
NS_IMETHODIMP DefaultURI::GetDisplayHost(nsACString& aDisplayHost) {
// At the moment it doesn't seem useful to decode the hostname if it happens
// to contain punycode.
return GetHost(aDisplayHost);
}
NS_IMETHODIMP DefaultURI::GetDisplayHostPort(nsACString& aDisplayHostPort) {
// At the moment it doesn't seem useful to decode the hostname if it happens
// to contain punycode.
return GetHostPort(aDisplayHostPort);
}
NS_IMETHODIMP DefaultURI::GetDisplaySpec(nsACString& aDisplaySpec) {
// At the moment it doesn't seem useful to decode the hostname if it happens
// to contain punycode.
return GetSpec(aDisplaySpec);
}
NS_IMETHODIMP DefaultURI::GetDisplayPrePath(nsACString& aDisplayPrePath) {
// At the moment it doesn't seem useful to decode the hostname if it happens
// to contain punycode.
return GetPrePath(aDisplayPrePath);
}
NS_IMETHODIMP DefaultURI::Mutate(nsIURIMutator** _retval) {
RefPtr<DefaultURI::Mutator> mutator = new DefaultURI::Mutator();
mutator->Init(this);
mutator.forget(_retval);
return NS_OK;
}
void DefaultURI::Serialize(ipc::URIParams& aParams) {
ipc::DefaultURIParams params;
params.spec() = mURL->Spec();
aParams = params;
}
//----------------------------------------------------------------------------
// nsIURIMutator
//----------------------------------------------------------------------------
NS_IMPL_ADDREF(DefaultURI::Mutator)
NS_IMPL_RELEASE(DefaultURI::Mutator)
NS_IMETHODIMP DefaultURI::Mutator::QueryInterface(REFNSIID aIID,
void** aInstancePtr) {
NS_ASSERTION(aInstancePtr, "QueryInterface requires a non-NULL destination!");
nsISupports* foundInterface = nullptr;
if (aIID.Equals(NS_GET_IID(nsIURI))) {
RefPtr<DefaultURI> defaultURI = new DefaultURI();
mMutator->Finalize(getter_AddRefs(defaultURI->mURL));
foundInterface =
static_cast<nsISupports*>(static_cast<nsIURI*>((defaultURI.get())));
NS_ADDREF(foundInterface);
*aInstancePtr = foundInterface;
return NS_OK;
}
if (aIID.Equals(NS_GET_IID(nsIURIMutator)) ||
aIID.Equals(NS_GET_IID(nsISupports))) {
foundInterface =
static_cast<nsISupports*>(static_cast<nsIURIMutator*>(this));
} else if (aIID.Equals(NS_GET_IID(nsIURISetters))) {
foundInterface =
static_cast<nsISupports*>(static_cast<nsIURISetters*>(this));
} else if (aIID.Equals(NS_GET_IID(nsIURISetSpec))) {
foundInterface =
static_cast<nsISupports*>(static_cast<nsIURISetSpec*>(this));
} else if (aIID.Equals(NS_GET_IID(nsISerializable))) {
foundInterface =
static_cast<nsISupports*>(static_cast<nsISerializable*>(this));
}
if (foundInterface) {
NS_ADDREF(foundInterface);
*aInstancePtr = foundInterface;
return NS_OK;
}
return NS_NOINTERFACE;
}
NS_IMETHODIMP DefaultURI::Mutator::Read(nsIObjectInputStream* aStream) {
nsAutoCString spec;
nsresult rv = aStream->ReadCString(spec);
if (NS_FAILED(rv)) {
return rv;
}
return SetSpec(spec, nullptr);
}
NS_IMETHODIMP DefaultURI::Mutator::Deserialize(
const mozilla::ipc::URIParams& aParams) {
if (aParams.type() != ipc::URIParams::TDefaultURIParams) {
NS_ERROR("Received unknown parameters from the other process!");
return NS_ERROR_FAILURE;
}
const ipc::DefaultURIParams& params = aParams.get_DefaultURIParams();
auto result = MozURL::Mutator::FromSpec(params.spec());
if (result.isErr()) {
return result.unwrapErr();
}
mMutator = Some(result.unwrap());
return NS_OK;
}
NS_IMETHODIMP DefaultURI::Mutator::Finalize(nsIURI** aURI) {
if (!mMutator.isSome()) {
return NS_ERROR_NOT_AVAILABLE;
}
RefPtr<DefaultURI> uri = new DefaultURI();
mMutator->Finalize(getter_AddRefs(uri->mURL));
mMutator = Nothing();
uri.forget(aURI);
return NS_OK;
}
NS_IMETHODIMP DefaultURI::Mutator::SetSpec(const nsACString& aSpec,
nsIURIMutator** aMutator) {
ASSIGN_AND_ADDREF_THIS(aMutator);
auto result = MozURL::Mutator::FromSpec(aSpec);
if (result.isErr()) {
return result.unwrapErr();
}
mMutator = Some(result.unwrap());
return NS_OK;
}
NS_IMETHODIMP
DefaultURI::Mutator::SetScheme(const nsACString& aScheme,
nsIURIMutator** aMutator) {
ASSIGN_AND_ADDREF_THIS(aMutator);
if (!mMutator.isSome()) {
return NS_ERROR_NULL_POINTER;
}
mMutator->SetScheme(aScheme);
return mMutator->GetStatus();
}
NS_IMETHODIMP
DefaultURI::Mutator::SetUserPass(const nsACString& aUserPass,
nsIURIMutator** aMutator) {
ASSIGN_AND_ADDREF_THIS(aMutator);
if (!mMutator.isSome()) {
return NS_ERROR_NULL_POINTER;
}
int32_t index = aUserPass.FindChar(':');
if (index == kNotFound) {
mMutator->SetUsername(aUserPass);
mMutator->SetPassword(EmptyCString());
return mMutator->GetStatus();
}
mMutator->SetUsername(Substring(aUserPass, 0, index));
nsresult rv = mMutator->GetStatus();
if (NS_FAILED(rv)) {
return rv;
}
mMutator->SetPassword(Substring(aUserPass, index + 1));
rv = mMutator->GetStatus();
if (NS_FAILED(rv)) {
return rv;
}
return NS_OK;
}
NS_IMETHODIMP
DefaultURI::Mutator::SetUsername(const nsACString& aUsername,
nsIURIMutator** aMutator) {
ASSIGN_AND_ADDREF_THIS(aMutator);
if (!mMutator.isSome()) {
return NS_ERROR_NULL_POINTER;
}
mMutator->SetUsername(aUsername);
return mMutator->GetStatus();
}
NS_IMETHODIMP
DefaultURI::Mutator::SetPassword(const nsACString& aPassword,
nsIURIMutator** aMutator) {
ASSIGN_AND_ADDREF_THIS(aMutator);
if (!mMutator.isSome()) {
return NS_ERROR_NULL_POINTER;
}
mMutator->SetPassword(aPassword);
return mMutator->GetStatus();
}
NS_IMETHODIMP
DefaultURI::Mutator::SetHostPort(const nsACString& aHostPort,
nsIURIMutator** aMutator) {
ASSIGN_AND_ADDREF_THIS(aMutator);
if (!mMutator.isSome()) {
return NS_ERROR_NULL_POINTER;
}
mMutator->SetHostPort(aHostPort);
return mMutator->GetStatus();
}
NS_IMETHODIMP
DefaultURI::Mutator::SetHost(const nsACString& aHost,
nsIURIMutator** aMutator) {
ASSIGN_AND_ADDREF_THIS(aMutator);
if (!mMutator.isSome()) {
return NS_ERROR_NULL_POINTER;
}
mMutator->SetHostname(aHost);
return mMutator->GetStatus();
}
NS_IMETHODIMP
DefaultURI::Mutator::SetPort(int32_t aPort, nsIURIMutator** aMutator) {
ASSIGN_AND_ADDREF_THIS(aMutator);
if (!mMutator.isSome()) {
return NS_ERROR_NULL_POINTER;
}
mMutator->SetPort(aPort);
return mMutator->GetStatus();
}
NS_IMETHODIMP
DefaultURI::Mutator::SetPathQueryRef(const nsACString& aPathQueryRef,
nsIURIMutator** aMutator) {
ASSIGN_AND_ADDREF_THIS(aMutator);
if (!mMutator.isSome()) {
return NS_ERROR_NULL_POINTER;
}
if (aPathQueryRef.IsEmpty()) {
mMutator->SetFilePath(EmptyCString());
mMutator->SetQuery(EmptyCString());
mMutator->SetRef(EmptyCString());
return mMutator->GetStatus();
}
nsAutoCString pathQueryRef(aPathQueryRef);
if (!StringBeginsWith(pathQueryRef, NS_LITERAL_CSTRING("/"))) {
pathQueryRef.Insert('/', 0);
}
RefPtr<MozURL> url;
mMutator->Finalize(getter_AddRefs(url));
mMutator = Nothing();
auto result = MozURL::Mutator::FromSpec(pathQueryRef, url);
if (result.isErr()) {
return result.unwrapErr();
}
mMutator = Some(result.unwrap());
return mMutator->GetStatus();
}
NS_IMETHODIMP
DefaultURI::Mutator::SetRef(const nsACString& aRef, nsIURIMutator** aMutator) {
ASSIGN_AND_ADDREF_THIS(aMutator);
if (!mMutator.isSome()) {
return NS_ERROR_NULL_POINTER;
}
mMutator->SetRef(aRef);
return mMutator->GetStatus();
}
NS_IMETHODIMP
DefaultURI::Mutator::SetFilePath(const nsACString& aFilePath,
nsIURIMutator** aMutator) {
ASSIGN_AND_ADDREF_THIS(aMutator);
if (!mMutator.isSome()) {
return NS_ERROR_NULL_POINTER;
}
mMutator->SetFilePath(aFilePath);
return mMutator->GetStatus();
}
NS_IMETHODIMP
DefaultURI::Mutator::SetQuery(const nsACString& aQuery,
nsIURIMutator** aMutator) {
ASSIGN_AND_ADDREF_THIS(aMutator);
if (!mMutator.isSome()) {
return NS_ERROR_NULL_POINTER;
}
mMutator->SetQuery(aQuery);
return mMutator->GetStatus();
}
NS_IMETHODIMP
DefaultURI::Mutator::SetQueryWithEncoding(const nsACString& aQuery,
const mozilla::Encoding* aEncoding,
nsIURIMutator** aMutator) {
ASSIGN_AND_ADDREF_THIS(aMutator);
if (!mMutator.isSome()) {
return NS_ERROR_NULL_POINTER;
}
// we only support UTF-8 for DefaultURI
mMutator->SetQuery(aQuery);
return mMutator->GetStatus();
}
} // namespace net
} // namespace mozilla

64
netwerk/base/DefaultURI.h Normal file
View File

@ -0,0 +1,64 @@
/* 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 DefaultURI_h__
#define DefaultURI_h__
#include "nsIURI.h"
#include "nsISerializable.h"
#include "nsIClassInfo.h"
#include "nsISizeOf.h"
#include "nsIURIMutator.h"
#include "mozilla/net/MozURL.h"
namespace mozilla {
namespace net {
class DefaultURI : public nsIURI,
public nsISerializable,
public nsIClassInfo,
public nsISizeOf {
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIURI
NS_DECL_NSISERIALIZABLE
NS_DECL_NSICLASSINFO
virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override;
virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override;
class Mutator final : public nsIURIMutator, public nsISerializable {
NS_DECL_ISUPPORTS
NS_DECL_NSIURISETSPEC
NS_DECL_NSIURISETTERS
NS_DECL_NSIURIMUTATOR
NS_IMETHOD
Write(nsIObjectOutputStream* aOutputStream) override {
MOZ_ASSERT_UNREACHABLE("nsIURIMutator.write() should never be called");
return NS_ERROR_NOT_IMPLEMENTED;
}
MOZ_MUST_USE NS_IMETHOD Read(nsIObjectInputStream* aStream) override;
explicit Mutator() = default;
private:
virtual ~Mutator() = default;
void Init(DefaultURI* aFrom) { mMutator = Some(aFrom->mURL->Mutate()); }
Maybe<MozURL::Mutator> mMutator;
friend class DefaultURI;
};
private:
virtual ~DefaultURI() = default;
RefPtr<MozURL> mURL;
};
} // namespace net
} // namespace mozilla
#endif // DefaultURI_h__

View File

@ -166,6 +166,7 @@ EXPORTS.mozilla.net += [
'ChannelDiverterParent.h',
'Dashboard.h',
'DashboardTypes.h',
'DefaultURI.h',
'IOActivityMonitor.h',
'MemoryDownloader.h',
'NetworkConnectivityService.h',
@ -186,6 +187,7 @@ UNIFIED_SOURCES += [
'ChannelDiverterChild.cpp',
'ChannelDiverterParent.cpp',
'Dashboard.cpp',
'DefaultURI.cpp',
'EventTokenBucket.cpp',
'IOActivityMonitor.cpp',
'LoadContextInfo.cpp',

View File

@ -7,6 +7,7 @@
#include "mozilla/net/MozURL_ffi.h"
#include "mozilla/RefPtr.h"
#include "mozilla/Result.h"
namespace mozilla {
namespace net {
@ -60,6 +61,8 @@ class MozURL final {
nsDependentCSubstring Ref() const { return mozurl_fragment(this); }
bool HasFragment() const { return mozurl_has_fragment(this); }
nsDependentCSubstring Directory() const { return mozurl_directory(this); }
nsDependentCSubstring PrePath() const { return mozurl_prepath(this); }
nsDependentCSubstring SpecNoRef() const { return mozurl_spec_no_ref(this); }
// This matches the definition of origins and base domains in nsIPrincipal for
// almost all URIs (some rare file:// URIs don't match and it would be hard to
@ -80,7 +83,9 @@ class MozURL final {
return mozurl_relative(this, aOther, aRelative);
}
class MOZ_STACK_CLASS Mutator {
size_t SizeOf() { return mozurl_sizeof(this); }
class Mutator {
public:
// Calling this method will result in the creation of a new MozURL that
// adopts the mutator's mURL.
@ -176,10 +181,30 @@ class MozURL final {
// if (NS_SUCCEEDED(rv)) { /* use url2 */ }
nsresult GetStatus() { return mURL ? mStatus : NS_ERROR_NOT_AVAILABLE; }
static Result<Mutator, nsresult> FromSpec(
const nsACString& aSpec, const MozURL* aBaseURL = nullptr) {
Mutator m = Mutator(aSpec, aBaseURL);
if (m.mURL) {
MOZ_ASSERT(NS_SUCCEEDED(m.mStatus));
return m;
}
MOZ_ASSERT(NS_FAILED(m.mStatus));
return Err(m.mStatus);
}
private:
explicit Mutator(MozURL* aUrl) : mStatus(NS_OK) {
mozurl_clone(aUrl, getter_AddRefs(mURL));
}
// This is only used to create a mutator from a string without cloning it
// so we avoid a pointless copy in FromSpec. It is important that we
// check the value of mURL afterwards.
explicit Mutator(const nsACString& aSpec,
const MozURL* aBaseURL = nullptr) {
mStatus = mozurl_new(getter_AddRefs(mURL), &aSpec, aBaseURL);
}
RefPtr<MozURL> mURL;
nsresult mStatus;
friend class MozURL;

View File

@ -55,9 +55,11 @@ MozURLSpecSlice mozurl_filepath(const mozilla::net::MozURL*);
MozURLSpecSlice mozurl_path(const mozilla::net::MozURL*);
MozURLSpecSlice mozurl_query(const mozilla::net::MozURL*);
MozURLSpecSlice mozurl_fragment(const mozilla::net::MozURL*);
MozURLSpecSlice mozurl_spec_no_ref(const mozilla::net::MozURL*);
bool mozurl_has_fragment(const mozilla::net::MozURL*);
MozURLSpecSlice mozurl_directory(const mozilla::net::MozURL*);
MozURLSpecSlice mozurl_prepath(const mozilla::net::MozURL*);
void mozurl_origin(const mozilla::net::MozURL*, nsACString* aResult);
nsresult mozurl_base_domain(const mozilla::net::MozURL*, nsACString* aResult);
@ -87,6 +89,8 @@ nsresult mozurl_set_query(mozilla::net::MozURL* aUrl, const nsACString* aQuery);
nsresult mozurl_set_fragment(mozilla::net::MozURL* aUrl,
const nsACString* aFragment);
size_t mozurl_sizeof(const mozilla::net::MozURL*);
// Utility function for parsing IPv6 addresses, used by nsStandardURL.h
//
// This function does not follow the mozurl_ naming convention, as it does not

View File

@ -25,6 +25,7 @@ use std::ptr;
use std::ops;
use std::marker::PhantomData;
use std::fmt::Write;
use std::mem;
extern "C" {
fn Gecko_StrictFileOriginPolicy() -> bool;
@ -237,6 +238,11 @@ pub extern "C" fn mozurl_fragment(url: &MozURL) -> SpecSlice {
url.fragment().unwrap_or("").into()
}
#[no_mangle]
pub extern "C" fn mozurl_spec_no_ref(url: &MozURL) -> SpecSlice {
(&url[..Position::AfterQuery]).into()
}
#[no_mangle]
pub extern "C" fn mozurl_has_fragment(url: &MozURL) -> bool {
url.fragment().is_some()
@ -251,6 +257,11 @@ pub extern "C" fn mozurl_directory(url: &MozURL) -> SpecSlice {
}
}
#[no_mangle]
pub extern "C" fn mozurl_prepath(url: &MozURL) -> SpecSlice {
(&url[..Position::BeforePath]).into()
}
fn get_origin(url: &MozURL) -> Option<String> {
match url.scheme() {
"blob" | "ftp" | "http" | "https" | "ws" | "wss" =>
@ -418,7 +429,7 @@ pub extern "C" fn mozurl_set_port_no(url: &mut MozURL, new_port: i32) -> nsresul
}
let port = match new_port {
new if new < 0 || u16::max_value() as i32 > new => None,
new if new < 0 || u16::max_value() as i32 <= new => None,
new if Some(new as u16) == default_port(url.scheme()) => None,
new => Some(new as u16),
};
@ -450,6 +461,12 @@ pub extern "C" fn mozurl_set_fragment(url: &mut MozURL, fragment: &nsACString) -
NS_OK
}
#[no_mangle]
pub extern "C" fn mozurl_sizeof(url: &MozURL) -> usize {
debug_assert_mut!(url);
mem::size_of::<MozURL>() + url.as_str().len()
}
#[no_mangle]
pub extern "C" fn mozurl_common_base(url1: &MozURL, url2: &MozURL, result: &mut *const MozURL) -> nsresult {
*result = ptr::null();

View File

@ -16,6 +16,7 @@
#include "mozilla/LoadInfo.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/Monitor.h"
#include "mozilla/StaticPrefs_network.h"
#include "mozilla/StaticPrefs_privacy.h"
#include "mozilla/StoragePrincipalHelper.h"
#include "mozilla/TaskQueue.h"
@ -86,6 +87,7 @@
#include "mozIThirdPartyUtil.h"
#include "../mime/nsMIMEHeaderParamImpl.h"
#include "nsStandardURL.h"
#include "DefaultURI.h"
#include "nsChromeProtocolHandler.h"
#include "nsJSProtocolHandler.h"
#include "nsDataHandler.h"
@ -1839,10 +1841,12 @@ nsresult NS_NewURI(nsIURI** aURI, const nsACString& aSpec,
// that have notion of hostname, authority and relative URLs. Below we
// manually check agains set of known protocols schemes until more general
// solution is in place (See Bug 1569733)
if (scheme.EqualsLiteral("dweb") || scheme.EqualsLiteral("dat") ||
scheme.EqualsLiteral("ipfs") || scheme.EqualsLiteral("ipns") ||
scheme.EqualsLiteral("ssb") || scheme.EqualsLiteral("wtp")) {
return NewStandardURI(aSpec, aCharset, aBaseURI, -1, aURI);
if (!StaticPrefs::network_url_useDefaultURI()) {
if (scheme.EqualsLiteral("dweb") || scheme.EqualsLiteral("dat") ||
scheme.EqualsLiteral("ipfs") || scheme.EqualsLiteral("ipns") ||
scheme.EqualsLiteral("ssb") || scheme.EqualsLiteral("wtp")) {
return NewStandardURI(aSpec, aCharset, aBaseURI, -1, aURI);
}
}
#if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
@ -1864,11 +1868,23 @@ nsresult NS_NewURI(nsIURI** aURI, const nsACString& aSpec,
MOZ_DIAGNOSTIC_ASSERT(newScheme == scheme);
}
if (StaticPrefs::network_url_useDefaultURI()) {
return NS_MutateURI(new DefaultURI::Mutator())
.SetSpec(newSpec)
.Finalize(aURI);
}
return NS_MutateURI(new nsSimpleURI::Mutator())
.SetSpec(newSpec)
.Finalize(aURI);
}
if (StaticPrefs::network_url_useDefaultURI()) {
return NS_MutateURI(new DefaultURI::Mutator())
.SetSpec(aSpec)
.Finalize(aURI);
}
// Falls back to external protocol handler.
return NS_MutateURI(new nsSimpleURI::Mutator()).SetSpec(aSpec).Finalize(aURI);
}

View File

@ -370,6 +370,13 @@ Classes = [
'headers': ['nsSimpleURI.h'],
'processes': ProcessSelector.ALLOW_IN_SOCKET_PROCESS,
},
{
'cid': '{04445aa0-fd27-4c99-bd41-6be6318ae92c}',
'contract_ids': ['@mozilla.org/network/default-uri-mutator;1'],
'type': 'mozilla::net::DefaultURI::Mutator',
'headers': ['/netwerk/base/DefaultURI.h'],
'processes': ProcessSelector.ALLOW_IN_SOCKET_PROCESS,
},
{
'cid': '{ad56b25f-e6bb-4db3-9f7b-5b7db33fd2b1}',
'contract_ids': ['@mozilla.org/network/socket-transport-service;1'],

View File

@ -0,0 +1,151 @@
"use strict";
function stringToDefaultURI(str) {
return Cc["@mozilla.org/network/default-uri-mutator;1"]
.createInstance(Ci.nsIURIMutator)
.setSpec(str)
.finalize();
}
add_task(function test_getters() {
let uri = stringToDefaultURI(
"proto://user:password@hostname:123/path/to/file?query#hash"
);
equal(uri.spec, "proto://user:password@hostname:123/path/to/file?query#hash");
equal(uri.prePath, "proto://user:password@hostname:123");
equal(uri.scheme, "proto");
equal(uri.userPass, "user:password");
equal(uri.username, "user");
equal(uri.password, "password");
equal(uri.hostPort, "hostname:123");
equal(uri.host, "hostname");
equal(uri.port, 123);
equal(uri.pathQueryRef, "/path/to/file?query#hash");
equal(uri.asciiSpec, uri.spec);
equal(uri.asciiHostPort, uri.hostPort);
equal(uri.asciiHost, uri.host);
equal(uri.ref, "hash");
equal(
uri.specIgnoringRef,
"proto://user:password@hostname:123/path/to/file?query"
);
equal(uri.hasRef, true);
equal(uri.filePath, "/path/to/file");
equal(uri.query, "query");
equal(uri.displayHost, uri.host);
equal(uri.displayHostPort, uri.hostPort);
equal(uri.displaySpec, uri.spec);
equal(uri.displayPrePath, uri.prePath);
});
add_task(function test_methods() {
let uri = stringToDefaultURI(
"proto://user:password@hostname:123/path/to/file?query#hash"
);
let uri_same = stringToDefaultURI(
"proto://user:password@hostname:123/path/to/file?query#hash"
);
let uri_different = stringToDefaultURI(
"proto://user:password@hostname:123/path/to/file?query"
);
let uri_very_different = stringToDefaultURI(
"proto://user:password@hostname:123/path/to/file?query1#hash"
);
ok(uri.equals(uri_same));
ok(!uri.equals(uri_different));
ok(uri.schemeIs("proto"));
ok(!uri.schemeIs("proto2"));
ok(!uri.schemeIs("proto "));
ok(!uri.schemeIs("proto\n"));
equal(uri.resolve("/hello"), "proto://user:password@hostname:123/hello");
equal(
uri.resolve("hello"),
"proto://user:password@hostname:123/path/to/hello"
);
equal(uri.resolve("proto2:otherhost"), "proto2:otherhost");
ok(uri.equalsExceptRef(uri_same));
ok(uri.equalsExceptRef(uri_different));
ok(!uri.equalsExceptRef(uri_very_different));
});
add_task(function test_mutator() {
let uri = stringToDefaultURI(
"proto://user:pass@host:123/path/to/file?query#hash"
);
let check = (callSetters, verify) => {
let m = uri.mutate();
callSetters(m);
verify(m.finalize());
};
check(m => m.setSpec("test:bla"), u => equal(u.spec, "test:bla"));
check(m => m.setSpec("test:bla"), u => equal(u.spec, "test:bla"));
check(
m => m.setScheme("some"),
u => equal(u.spec, "some://user:pass@host:123/path/to/file?query#hash")
);
check(
m => m.setUserPass("u"),
u => equal(u.spec, "proto://u@host:123/path/to/file?query#hash")
);
check(
m => m.setUserPass("u:p"),
u => equal(u.spec, "proto://u:p@host:123/path/to/file?query#hash")
);
check(
m => m.setUserPass(":p"),
u => equal(u.spec, "proto://:p@host:123/path/to/file?query#hash")
);
check(
m => m.setUserPass(""),
u => equal(u.spec, "proto://host:123/path/to/file?query#hash")
);
check(
m => m.setUsername("u"),
u => equal(u.spec, "proto://u:pass@host:123/path/to/file?query#hash")
);
check(
m => m.setPassword("p"),
u => equal(u.spec, "proto://user:p@host:123/path/to/file?query#hash")
);
check(
m => m.setHostPort("h"),
u => equal(u.spec, "proto://user:pass@h:123/path/to/file?query#hash")
);
check(
m => m.setHostPort("h:456"),
u => equal(u.spec, "proto://user:pass@h:456/path/to/file?query#hash")
);
check(
m => m.setHost("bla"),
u => equal(u.spec, "proto://user:pass@bla:123/path/to/file?query#hash")
);
check(
m => m.setPort(987),
u => equal(u.spec, "proto://user:pass@host:987/path/to/file?query#hash")
);
check(
m => m.setPathQueryRef("/p?q#r"),
u => equal(u.spec, "proto://user:pass@host:123/p?q#r")
);
check(
m => m.setRef("r"),
u => equal(u.spec, "proto://user:pass@host:123/path/to/file?query#r")
);
check(
m => m.setFilePath("/my/path"),
u => equal(u.spec, "proto://user:pass@host:123/my/path?query#hash")
);
check(
m => m.setQuery("q"),
u => equal(u.spec, "proto://user:pass@host:123/path/to/file?q#hash")
);
});
add_task(function test_ipv6() {
let uri = stringToDefaultURI("non-special://[2001::1]/");
equal(uri.hostPort, "[2001::1]");
// Hopefully this will change after bug 1603199.
equal(uri.host, "2001::1");
});

View File

@ -447,3 +447,4 @@ skip-if = os == "android"
skip-if = os == "android" # node server doesn't run on android
[test_loadgroup_cancel.js]
[test_obs-fold.js]
[test_defaultURI.js]