--- a/netwerk/base/nsStandardURL.cpp
+++ b/netwerk/base/nsStandardURL.cpp
@@ -287,22 +287,22 @@ nsSegmentEncoder::EncodeSegment(const ns
#ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
static LinkedList<nsStandardURL> gAllURLs;
#endif
nsStandardURL::nsStandardURL(bool aSupportsFileURL, bool aTrackURL)
: mDefaultPort(-1)
, mPort(-1)
- , mHostA(nullptr)
- , mHostEncoding(eEncoding_ASCII)
+ , mDisplayHost(nullptr)
, mSpecEncoding(eEncoding_Unknown)
, mURLType(URLTYPE_STANDARD)
, mMutable(true)
, mSupportsFileURL(aSupportsFileURL)
+ , mCheckedIfHostA(false)
{
LOG(("Creating nsStandardURL @%p\n", this));
if (!gInitialized) {
gInitialized = true;
InitGlobalObjects();
}
@@ -322,20 +322,16 @@ nsStandardURL::nsStandardURL(bool aSuppo
mRustURL = new RustURL();
}
#endif
}
nsStandardURL::~nsStandardURL()
{
LOG(("Destroying nsStandardURL @%p\n", this));
-
- if (mHostA) {
- free(mHostA);
- }
}
#ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
struct DumpLeakedURLs {
DumpLeakedURLs() {}
~DumpLeakedURLs();
};
@@ -391,39 +387,37 @@ nsStandardURL::Clear()
mPort = -1;
mScheme.Reset();
mAuthority.Reset();
mUsername.Reset();
mPassword.Reset();
mHost.Reset();
- mHostEncoding = eEncoding_ASCII;
mPath.Reset();
mFilepath.Reset();
mDirectory.Reset();
mBasename.Reset();
mExtension.Reset();
mQuery.Reset();
mRef.Reset();
InvalidateCache();
}
void
nsStandardURL::InvalidateCache(bool invalidateCachedFile)
{
- if (invalidateCachedFile)
+ if (invalidateCachedFile) {
mFile = nullptr;
- if (mHostA) {
- free(mHostA);
- mHostA = nullptr;
}
+ mDisplayHost.Truncate();
+ mCheckedIfHostA = false;
mSpecEncoding = eEncoding_Unknown;
}
// Return the number of "dots" in the string, or -1 if invalid. Note that the
// number of relevant entries in the bases/starts/ends arrays is number of
// dots + 1.
// Since the trailing dot is allowed, we pass and adjust "length".
//
@@ -635,42 +629,54 @@ nsStandardURL::NormalizeIPv4(const nsACS
nsresult
nsStandardURL::NormalizeIDN(const nsACString& host, nsCString& result)
{
// If host is ACE, then convert to UTF-8. Else, if host is already UTF-8,
// then make sure it is normalized per IDN.
// this function returns true if normalization succeeds.
- // NOTE: As a side-effect this function sets mHostEncoding. While it would
- // be nice to avoid side-effects in this function, the implementation of
- // this function is already somewhat bound to the behavior of the
- // callsites. Anyways, this function exists to avoid code duplication, so
- // side-effects abound :-/
-
- NS_ASSERTION(mHostEncoding == eEncoding_ASCII, "unexpected default encoding");
-
- bool isASCII;
if (!gIDN) {
nsCOMPtr<nsIIDNService> serv(do_GetService(NS_IDNSERVICE_CONTRACTID));
if (serv) {
NS_ADDREF(gIDN = serv.get());
}
}
result.Truncate();
- nsresult rv = NS_ERROR_UNEXPECTED;
- if (gIDN) {
- rv = gIDN->ConvertToDisplayIDN(host, &isASCII, result);
- if (NS_SUCCEEDED(rv) && !isASCII) {
- mHostEncoding = eEncoding_UTF8;
- }
+ nsresult rv;
+
+ if (!gIDN) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ bool isAscii;
+ nsAutoCString normalized;
+ rv = gIDN->ConvertToDisplayIDN(host, &isAscii, normalized);
+ if (NS_FAILED(rv)) {
+ return rv;
}
- return rv;
+ // The result is ASCII. No need to convert to ACE.
+ if (isAscii) {
+ result = normalized;
+ mCheckedIfHostA = true;
+ mDisplayHost.Truncate();
+ return NS_OK;
+ }
+
+ rv = gIDN->ConvertUTF8toACE(normalized, result);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ mCheckedIfHostA = true;
+ mDisplayHost = normalized;
+
+ return NS_OK;
}
bool
nsStandardURL::ValidIPv6orHostname(const char *host, uint32_t length)
{
if (!host || !*host) {
// Should not be NULL or empty string
return false;
@@ -820,17 +826,16 @@ nsStandardURL::BuildNormalizedSpec(const
approxLen += 1 + encoder.EncodeSegmentCount(spec, mRef, esc_Ref,
encRef, useEncRef);
}
}
// do not escape the hostname, if IPv6 address literal, mHost will
// already point to a [ ] delimited IPv6 address literal.
// However, perform Unicode normalization on it, as IDN does.
- mHostEncoding = eEncoding_ASCII;
// Note that we don't disallow URLs without a host - file:, etc
if (mHost.mLen > 0) {
nsAutoCString tempHost;
NS_UnescapeURL(spec + mHost.mPos, mHost.mLen, esc_AlwaysCopy | esc_Host, tempHost);
if (tempHost.Contains('\0'))
return NS_ERROR_MALFORMED_URI; // null embedded in hostname
if (tempHost.Contains(' '))
return NS_ERROR_MALFORMED_URI; // don't allow spaces in the hostname
@@ -1340,45 +1345,110 @@ nsStandardURL::GetSpec(nsACString &resul
CALL_RUST_GETTER_STR(result, GetSpec, result);
return NS_OK;
}
// result may contain unescaped UTF-8 characters
NS_IMETHODIMP
nsStandardURL::GetSensitiveInfoHiddenSpec(nsACString &result)
{
- result = mSpec;
+ nsresult rv = GetSpec(result);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
if (mPassword.mLen >= 0) {
result.Replace(mPassword.mPos, mPassword.mLen, "****");
}
CALL_RUST_GETTER_STR(result, GetSensitiveInfoHiddenSpec, result);
return NS_OK;
}
// result may contain unescaped UTF-8 characters
NS_IMETHODIMP
nsStandardURL::GetSpecIgnoringRef(nsACString &result)
{
// URI without ref is 0 to one char before ref
- if (mRef.mLen >= 0) {
- URLSegment noRef(0, mRef.mPos - 1);
-
- result = Segment(noRef);
- } else {
- result = mSpec;
+ if (mRef.mLen < 0) {
+ return GetSpec(result);
}
+
+ URLSegment noRef(0, mRef.mPos - 1);
+ result = Segment(noRef);
+
+ if (!gPunycodeHost && mCheckedIfHostA && !mDisplayHost.IsEmpty()) {
+ result.Replace(mHost.mPos, mHost.mLen, mDisplayHost);
+ }
+
CALL_RUST_GETTER_STR(result, GetSpecIgnoringRef, result);
return NS_OK;
}
+NS_IMETHODIMP
+nsStandardURL::GetDisplaySpec(nsACString &aUnicodeSpec)
+{
+ aUnicodeSpec.Assign(mSpec);
+ if (mCheckedIfHostA && !mDisplayHost.IsEmpty()) {
+ aUnicodeSpec.Replace(mHost.mPos, mHost.mLen, mDisplayHost);
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsStandardURL::GetDisplayHostPort(nsACString &aUnicodeHostPort)
+{
+ nsresult rv = GetDisplayHost(aUnicodeHostPort);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ uint32_t pos = mHost.mPos + mHost.mLen;
+ if (pos < mPath.mPos)
+ aUnicodeHostPort += Substring(mSpec, pos, mPath.mPos - pos);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsStandardURL::GetDisplayHost(nsACString &aUnicodeHost)
+{
+ if (mCheckedIfHostA) {
+ if (mDisplayHost.IsEmpty()) {
+ return GetAsciiHost(aUnicodeHost);
+ } else {
+ aUnicodeHost = mDisplayHost;
+ return NS_OK;
+ }
+ }
+
+ if (!gIDN) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
+
+ nsresult rv = gIDN->ConvertACEtoUTF8(Host(), aUnicodeHost);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ mCheckedIfHostA = true;
+ if (aUnicodeHost != Host()) {
+ mDisplayHost = aUnicodeHost;
+ }
+
+ return NS_OK;
+}
+
+
// result may contain unescaped UTF-8 characters
NS_IMETHODIMP
nsStandardURL::GetPrePath(nsACString &result)
{
result = Prepath();
+ if (!gPunycodeHost && mCheckedIfHostA && !mDisplayHost.IsEmpty()) {
+ result.Replace(mHost.mPos, mHost.mLen, mDisplayHost);
+ }
CALL_RUST_GETTER_STR(result, GetPrePath, result);
return NS_OK;
}
// result is strictly US-ASCII
NS_IMETHODIMP
nsStandardURL::GetScheme(nsACString &result)
{
@@ -1412,27 +1482,27 @@ nsStandardURL::GetPassword(nsACString &r
result = Password();
CALL_RUST_GETTER_STR(result, GetPassword, result);
return NS_OK;
}
NS_IMETHODIMP
nsStandardURL::GetHostPort(nsACString &result)
{
- result = Hostport();
+ nsresult rv = GetAsciiHostPort(result);
CALL_RUST_GETTER_STR(result, GetHostPort, result);
- return NS_OK;
+ return rv;
}
NS_IMETHODIMP
nsStandardURL::GetHost(nsACString &result)
{
- result = Host();
+ nsresult rv = GetAsciiHost(result);
CALL_RUST_GETTER_STR(result, GetHost, result);
- return NS_OK;
+ return rv;
}
NS_IMETHODIMP
nsStandardURL::GetPort(int32_t *result)
{
// should never be more than 16 bit
MOZ_ASSERT(mPort <= std::numeric_limits<uint16_t>::max());
*result = mPort;
@@ -1486,67 +1556,26 @@ nsStandardURL::GetAsciiSpec(nsACString &
CALL_RUST_GETTER_STR(result, GetAsciiSpec, result);
return NS_OK;
}
// result is ASCII
NS_IMETHODIMP
nsStandardURL::GetAsciiHostPort(nsACString &result)
{
- if (mHostEncoding == eEncoding_ASCII) {
- result = Hostport();
- CALL_RUST_GETTER_STR(result, GetAsciiHostPort, result);
- return NS_OK;
- }
-
- MOZ_ALWAYS_SUCCEEDS(GetAsciiHost(result));
-
- // As our mHostEncoding is not eEncoding_ASCII, we know that
- // the our host is not ipv6, and we can avoid looking at it.
- MOZ_ASSERT(result.FindChar(':') == -1, "The host must not be ipv6");
-
- // hostport = "hostA" + ":port"
- uint32_t pos = mHost.mPos + mHost.mLen;
- if (pos < mPath.mPos)
- result += Substring(mSpec, pos, mPath.mPos - pos);
-
+ result = Hostport();
CALL_RUST_GETTER_STR(result, GetAsciiHostPort, result);
return NS_OK;
}
// result is ASCII
NS_IMETHODIMP
nsStandardURL::GetAsciiHost(nsACString &result)
{
- if (mHostEncoding == eEncoding_ASCII) {
- result = Host();
- CALL_RUST_GETTER_STR(result, GetAsciiHost, result);
- return NS_OK;
- }
-
- // perhaps we have it cached...
- if (mHostA) {
- result = mHostA;
- CALL_RUST_GETTER_STR(result, GetAsciiHost, result);
- return NS_OK;
- }
-
- if (gIDN) {
- nsresult rv;
- rv = gIDN->ConvertUTF8toACE(Host(), result);
- CALL_RUST_GETTER_STR(result, GetAsciiHost, result);
- if (NS_SUCCEEDED(rv)) {
- mHostA = ToNewCString(result);
- return NS_OK;
- }
- NS_WARNING("nsIDNService::ConvertUTF8toACE failed");
- }
-
- // something went wrong... guess all we can do is URL escape :-/
- NS_EscapeURL(Host(), esc_OnlyNonASCII | esc_AlwaysCopy, result);
+ result = Host();
CALL_RUST_GETTER_STR(result, GetAsciiHost, result);
return NS_OK;
}
NS_IMETHODIMP
nsStandardURL::GetOriginCharset(nsACString &result)
{
if (mOriginCharset.IsEmpty())
@@ -2079,17 +2108,16 @@ nsStandardURL::SetHost(const nsACString
if (strchr(host, ' '))
return NS_ERROR_MALFORMED_URI;
if (mSpec.Length() + strlen(host) - Host().Length() > (uint32_t) net_GetURLMaxLength()) {
return NS_ERROR_MALFORMED_URI;
}
InvalidateCache();
- mHostEncoding = eEncoding_ASCII;
uint32_t len;
nsAutoCString hostBuf;
nsresult rv = NormalizeIDN(flat, hostBuf);
if (NS_FAILED(rv)) {
return rv;
}
@@ -2402,17 +2430,17 @@ nsStandardURL::CloneInternal(nsStandardU
nsIURI **result)
{
RefPtr<nsStandardURL> clone = StartClone();
if (!clone)
return NS_ERROR_OUT_OF_MEMORY;
// Copy local members into clone.
- // Also copies the cached members mFile, mHostA
+ // Also copies the cached members mFile, mDisplayHost
clone->CopyMembers(this, refHandlingMode, newRef, true);
clone.forget(result);
return NS_OK;
}
nsresult nsStandardURL::CopyMembers(nsStandardURL * source,
nsStandardURL::RefHandlingEnum refHandlingMode, const nsACString& newRef,
@@ -2433,28 +2461,25 @@ nsresult nsStandardURL::CopyMembers(nsSt
mExtension = source->mExtension;
mQuery = source->mQuery;
mRef = source->mRef;
mOriginCharset = source->mOriginCharset;
mURLType = source->mURLType;
mParser = source->mParser;
mMutable = true;
mSupportsFileURL = source->mSupportsFileURL;
- mHostEncoding = source->mHostEncoding;
COPY_RUST_MEMBER;
if (copyCached) {
mFile = source->mFile;
- mHostA = source->mHostA ? strdup(source->mHostA) : nullptr;
+ mCheckedIfHostA = source->mCheckedIfHostA;
+ mDisplayHost = source->mDisplayHost;
mSpecEncoding = source->mSpecEncoding;
} else {
- // The same state as after calling InvalidateCache()
- mFile = nullptr;
- mHostA = nullptr;
- mSpecEncoding = eEncoding_Unknown;
+ InvalidateCache(true);
}
if (refHandlingMode == eIgnoreRef) {
SetRef(EmptyCString());
} else if (refHandlingMode == eReplaceRef) {
SetRef(newRef);
}
@@ -3424,17 +3449,17 @@ nsStandardURL::SetMutable(bool value)
//----------------------------------------------------------------------------
// nsStandardURL::nsISerializable
//----------------------------------------------------------------------------
NS_IMETHODIMP
nsStandardURL::Read(nsIObjectInputStream *stream)
{
- NS_PRECONDITION(!mHostA, "Shouldn't have cached ASCII host");
+ NS_PRECONDITION(mDisplayHost.IsEmpty(), "Shouldn't have cached unicode host");
NS_PRECONDITION(mSpecEncoding == eEncoding_Unknown,
"Shouldn't have spec encoding here");
nsresult rv;
uint32_t urlType;
rv = stream->Read32(&urlType);
if (NS_FAILED(rv)) return rv;
@@ -3512,25 +3537,16 @@ nsStandardURL::Read(nsIObjectInputStream
if (NS_FAILED(rv)) return rv;
mMutable = isMutable;
bool supportsFileURL;
rv = stream->ReadBoolean(&supportsFileURL);
if (NS_FAILED(rv)) return rv;
mSupportsFileURL = supportsFileURL;
- uint32_t hostEncoding;
- rv = stream->Read32(&hostEncoding);
- if (NS_FAILED(rv)) return rv;
- if (hostEncoding != eEncoding_ASCII && hostEncoding != eEncoding_UTF8) {
- NS_WARNING("Unexpected host encoding");
- return NS_ERROR_UNEXPECTED;
- }
- mHostEncoding = hostEncoding;
-
// wait until object is set up, then modify path to include the param
if (old_param.mLen >= 0) { // note that mLen=0 is ";"
// If this wasn't empty, it marks characters between the end of the
// file and start of the query - mPath should include the param,
// query and ref already. Bump the mFilePath and
// directory/basename/extension components to include this.
mFilepath.Merge(mSpec, ';', old_param);
mDirectory.Merge(mSpec, ';', old_param);
@@ -3609,20 +3625,17 @@ nsStandardURL::Write(nsIObjectOutputStre
if (NS_FAILED(rv)) return rv;
rv = stream->WriteBoolean(mMutable);
if (NS_FAILED(rv)) return rv;
rv = stream->WriteBoolean(mSupportsFileURL);
if (NS_FAILED(rv)) return rv;
- rv = stream->Write32(mHostEncoding);
- if (NS_FAILED(rv)) return rv;
-
- // mSpecEncoding and mHostA are just caches that can be recovered as needed.
+ // mSpecEncoding and mDisplayHost are just caches that can be recovered as needed.
return NS_OK;
}
//---------------------------------------------------------------------------
// nsStandardURL::nsIIPCSerializableURI
//---------------------------------------------------------------------------
@@ -3661,26 +3674,25 @@ nsStandardURL::Serialize(URIParams& aPar
params.directory() = ToIPCSegment(mDirectory);
params.baseName() = ToIPCSegment(mBasename);
params.extension() = ToIPCSegment(mExtension);
params.query() = ToIPCSegment(mQuery);
params.ref() = ToIPCSegment(mRef);
params.originCharset() = mOriginCharset;
params.isMutable() = !!mMutable;
params.supportsFileURL() = !!mSupportsFileURL;
- params.hostEncoding() = mHostEncoding;
- // mSpecEncoding and mHostA are just caches that can be recovered as needed.
+ // mSpecEncoding and mDisplayHost are just caches that can be recovered as needed.
aParams = params;
}
bool
nsStandardURL::Deserialize(const URIParams& aParams)
{
- NS_PRECONDITION(!mHostA, "Shouldn't have cached ASCII host");
+ NS_PRECONDITION(mDisplayHost.IsEmpty(), "Shouldn't have cached unicode host");
NS_PRECONDITION(mSpecEncoding == eEncoding_Unknown,
"Shouldn't have spec encoding here");
NS_PRECONDITION(!mFile, "Shouldn't have cached file");
if (aParams.type() != URIParams::TStandardURLParams) {
NS_ERROR("Received unknown parameters from the other process!");
return false;
}
@@ -3698,22 +3710,16 @@ nsStandardURL::Deserialize(const URIPara
case URLTYPE_NO_AUTHORITY:
mParser = net_GetNoAuthURLParser();
break;
default:
NS_NOTREACHED("bad urlType");
return false;
}
- if (params.hostEncoding() != eEncoding_ASCII &&
- params.hostEncoding() != eEncoding_UTF8) {
- NS_WARNING("Unexpected host encoding");
- return false;
- }
-
mPort = params.port();
mDefaultPort = params.defaultPort();
mSpec = params.spec();
mScheme = FromIPCSegment(params.scheme());
mAuthority = FromIPCSegment(params.authority());
mUsername = FromIPCSegment(params.username());
mPassword = FromIPCSegment(params.password());
mHost = FromIPCSegment(params.host());
@@ -3722,21 +3728,20 @@ nsStandardURL::Deserialize(const URIPara
mDirectory = FromIPCSegment(params.directory());
mBasename = FromIPCSegment(params.baseName());
mExtension = FromIPCSegment(params.extension());
mQuery = FromIPCSegment(params.query());
mRef = FromIPCSegment(params.ref());
mOriginCharset = params.originCharset();
mMutable = params.isMutable();
mSupportsFileURL = params.supportsFileURL();
- mHostEncoding = params.hostEncoding();
CALL_RUST_SYNC;
- // mSpecEncoding and mHostA are just caches that can be recovered as needed.
+ // mSpecEncoding and mDisplayHost are just caches that can be recovered as needed.
return true;
}
//----------------------------------------------------------------------------
// nsStandardURL::nsIClassInfo
//----------------------------------------------------------------------------
NS_IMETHODIMP
@@ -3795,17 +3800,17 @@ nsStandardURL::GetClassIDNoAlloc(nsCID *
// nsStandardURL::nsISizeOf
//----------------------------------------------------------------------------
size_t
nsStandardURL::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
{
return mSpec.SizeOfExcludingThisIfUnshared(aMallocSizeOf) +
mOriginCharset.SizeOfExcludingThisIfUnshared(aMallocSizeOf) +
- aMallocSizeOf(mHostA);
+ mDisplayHost.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
// Measurement of the following members may be added later if DMD finds it is
// worthwhile:
// - mParser
// - mFile
}
size_t