Bug 945240 - Make nsIURI.host & variants return ASCII strings r=mcmanus

* nsStandardURL::GetHost/GetHostPort/GetSpec contain an punycode encoded hostname.
* Added nsIURI::GetDisplayHost/GetDisplayHostPort/GetDisplaySpec which have unicode hostnames, depending on the hostname, character blacklist and the network.IDN_show_punycode pref
* remove mHostEncoding since it's not needed anymore (the hostname is always ASCII encoded)
* Add mCheckedIfHostA to know when GetDisplayHost can return the regular host, or when we need to use the cached mDisplayHost

MozReview-Commit-ID: 4qV9Ynhr2Jl
* * *
Bug 945240 - Make sure nsIURI.specIgnoringRef/.getSensitiveInfoHiddenSpec/.prePath contain unicode hosts when network.standard-url.punycode-host is set to false r=mcmanus

MozReview-Commit-ID: F6bZuHOWEsj

--HG--
extra : rebase_source : d8ae8bf774eb22b549370ca96565bafc930faf51
This commit is contained in:
Valentin Gosu 2017-07-11 19:09:10 +02:00
Родитель b08120ea47
Коммит f957fd9eef
8 изменённых файлов: 221 добавлений и 126 удалений

Просмотреть файл

@ -349,6 +349,24 @@ NullPrincipalURI::SchemeIs(const char* aScheme, bool* _schemeIs)
return NS_OK;
}
NS_IMETHODIMP
NullPrincipalURI::GetDisplaySpec(nsACString &aUnicodeSpec)
{
return GetSpec(aUnicodeSpec);
}
NS_IMETHODIMP
NullPrincipalURI::GetDisplayHostPort(nsACString &aUnicodeHostPort)
{
return GetHostPort(aUnicodeHostPort);
}
NS_IMETHODIMP
NullPrincipalURI::GetDisplayHost(nsACString &aUnicodeHost)
{
return GetHost(aUnicodeHost);
}
////////////////////////////////////////////////////////////////////////////////
//// nsIIPCSerializableURI

Просмотреть файл

@ -117,6 +117,24 @@ nsMozIconURI::GetSpecIgnoringRef(nsACString& result)
return GetSpec(result);
}
NS_IMETHODIMP
nsMozIconURI::GetDisplaySpec(nsACString& aUnicodeSpec)
{
return GetSpec(aUnicodeSpec);
}
NS_IMETHODIMP
nsMozIconURI::GetDisplayHostPort(nsACString& aUnicodeHostPort)
{
return GetHostPort(aUnicodeHostPort);
}
NS_IMETHODIMP
nsMozIconURI::GetDisplayHost(nsACString& aUnicodeHost)
{
return GetHost(aUnicodeHost);
}
NS_IMETHODIMP
nsMozIconURI::GetHasRef(bool* result)
{

Просмотреть файл

@ -46,7 +46,6 @@ struct StandardURLParams
nsCString originCharset;
bool isMutable;
bool supportsFileURL;
uint32_t hostEncoding;
};
struct JARURIParams

Просмотреть файл

@ -228,6 +228,24 @@ nsJARURI::GetSpecIgnoringRef(nsACString &aSpec)
return FormatSpec(entrySpec, aSpec);
}
NS_IMETHODIMP
nsJARURI::GetDisplaySpec(nsACString &aUnicodeSpec)
{
return GetSpec(aUnicodeSpec);
}
NS_IMETHODIMP
nsJARURI::GetDisplayHostPort(nsACString &aUnicodeHostPort)
{
return GetHostPort(aUnicodeHostPort);
}
NS_IMETHODIMP
nsJARURI::GetDisplayHost(nsACString &aUnicodeHost)
{
return GetHost(aUnicodeHost);
}
NS_IMETHODIMP
nsJARURI::GetHasRef(bool *result)
{

Просмотреть файл

@ -139,8 +139,6 @@ interface nsIURI : nsISupports
*
* If this attribute is set to a value that only has a host part, the port
* will not be reset. To reset the port as well use setHostAndPort.
*
* Characters are NOT escaped.
*/
attribute AUTF8String hostPort;
@ -152,10 +150,8 @@ interface nsIURI : nsISupports
/**
* The host is the internet domain name to which this URI refers. It could
* be an IPv4 (or IPv6) address literal. If supported, it could be a
* non-ASCII internationalized domain name.
*
* Characters are NOT escaped.
* be an IPv4 (or IPv6) address literal. Otherwise it is an ASCII or punycode
* encoded string.
*/
attribute AUTF8String host;
@ -307,4 +303,24 @@ interface nsIURI : nsISupports
* Some characters may be escaped.
*/
attribute AUTF8String query;
/**
* If the URI has a punycode encoded hostname, this will hold the UTF8
* representation of that hostname (if that representation doesn't contain
* blacklisted characters, and the network.IDN_show_punycode pref is false)
* Otherwise, if the hostname is ASCII, it will return the same as .asciiHost
*/
readonly attribute AUTF8String displayHost;
/**
* The displayHost:port (or simply the displayHost, if port == -1).
*/
readonly attribute AUTF8String displayHostPort;
/**
* Returns the same as calling .spec, only with a UTF8 encoded hostname
* (if that hostname doesn't contain blacklisted characters, and
* the network.IDN_show_punycode pref is false)
*/
readonly attribute AUTF8String displaySpec;
};

Просмотреть файл

@ -242,6 +242,24 @@ nsSimpleURI::GetSpecIgnoringRef(nsACString &result)
return NS_OK;
}
NS_IMETHODIMP
nsSimpleURI::GetDisplaySpec(nsACString &aUnicodeSpec)
{
return GetSpec(aUnicodeSpec);
}
NS_IMETHODIMP
nsSimpleURI::GetDisplayHostPort(nsACString &aUnicodeHostPort)
{
return GetHostPort(aUnicodeHostPort);
}
NS_IMETHODIMP
nsSimpleURI::GetDisplayHost(nsACString &aUnicodeHost)
{
return GetHost(aUnicodeHost);
}
NS_IMETHODIMP
nsSimpleURI::GetHasRef(bool *result)
{

Просмотреть файл

@ -292,12 +292,12 @@ static LinkedList<nsStandardURL> gAllURLs;
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));
@ -327,10 +327,6 @@ nsStandardURL::nsStandardURL(bool aSupportsFileURL, bool aTrackURL)
nsStandardURL::~nsStandardURL()
{
LOG(("Destroying nsStandardURL @%p\n", this));
if (mHostA) {
free(mHostA);
}
}
#ifdef DEBUG_DUMP_URLS_AT_SHUTDOWN
@ -396,7 +392,6 @@ nsStandardURL::Clear()
mUsername.Reset();
mPassword.Reset();
mHost.Reset();
mHostEncoding = eEncoding_ASCII;
mPath.Reset();
mFilepath.Reset();
@ -413,12 +408,11 @@ nsStandardURL::Clear()
void
nsStandardURL::InvalidateCache(bool invalidateCachedFile)
{
if (invalidateCachedFile)
if (invalidateCachedFile) {
mFile = nullptr;
if (mHostA) {
free(mHostA);
mHostA = nullptr;
}
mDisplayHost.Truncate();
mCheckedIfHostA = false;
mSpecEncoding = eEncoding_Unknown;
}
@ -640,15 +634,6 @@ nsStandardURL::NormalizeIDN(const nsACString& host, nsCString& result)
// 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) {
@ -657,15 +642,36 @@ nsStandardURL::NormalizeIDN(const nsACString& host, nsCString& result)
}
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;
}
return rv;
bool isAscii;
nsAutoCString normalized;
rv = gIDN->ConvertToDisplayIDN(host, &isAscii, normalized);
if (NS_FAILED(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
@ -825,7 +831,6 @@ nsStandardURL::BuildNormalizedSpec(const char *spec)
// 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;
@ -1345,7 +1350,10 @@ nsStandardURL::GetSpec(nsACString &result)
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, "****");
}
@ -1358,22 +1366,84 @@ 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;
}
@ -1417,17 +1487,17 @@ nsStandardURL::GetPassword(nsACString &result)
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
@ -1491,23 +1561,7 @@ nsStandardURL::GetAsciiSpec(nsACString &result)
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;
}
@ -1516,32 +1570,7 @@ nsStandardURL::GetAsciiHostPort(nsACString &result)
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;
}
@ -2084,7 +2113,6 @@ nsStandardURL::SetHost(const nsACString &input)
}
InvalidateCache();
mHostEncoding = eEncoding_ASCII;
uint32_t len;
nsAutoCString hostBuf;
@ -2407,7 +2435,7 @@ nsStandardURL::CloneInternal(nsStandardURL::RefHandlingEnum refHandlingMode,
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);
@ -2438,18 +2466,15 @@ nsresult nsStandardURL::CopyMembers(nsStandardURL * source,
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) {
@ -3429,7 +3454,7 @@ nsStandardURL::SetMutable(bool value)
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");
@ -3517,15 +3542,6 @@ nsStandardURL::Read(nsIObjectInputStream *stream)
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
@ -3614,10 +3630,7 @@ nsStandardURL::Write(nsIObjectOutputStream *stream)
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;
}
@ -3666,8 +3679,7 @@ nsStandardURL::Serialize(URIParams& aParams)
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;
}
@ -3675,7 +3687,7 @@ nsStandardURL::Serialize(URIParams& aParams)
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");
@ -3703,12 +3715,6 @@ nsStandardURL::Deserialize(const URIParams& aParams)
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();
@ -3727,11 +3733,10 @@ nsStandardURL::Deserialize(const URIParams& aParams)
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;
}
@ -3800,7 +3805,7 @@ 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:

Просмотреть файл

@ -168,7 +168,7 @@ protected:
const nsACString& newRef,
nsIURI** aClone);
// Helper method that copies member variables from the source StandardURL
// if copyCached = true, it will also copy mFile and mHostA
// if copyCached = true, it will also copy mFile and mDisplayHost
nsresult CopyMembers(nsStandardURL * source, RefHandlingEnum mode,
const nsACString& newRef,
bool copyCached = false);
@ -281,7 +281,8 @@ protected:
nsCOMPtr<nsIFile> mFile; // cached result for nsIFileURL::GetFile
private:
char *mHostA; // cached result for nsIURI::GetHostA
// cached result for nsIURI::GetDisplayHost
nsCString mDisplayHost;
enum {
eEncoding_Unknown,
@ -289,11 +290,13 @@ private:
eEncoding_UTF8
};
uint32_t mHostEncoding : 2; // eEncoding_xxx
uint32_t mSpecEncoding : 2; // eEncoding_xxx
uint32_t mURLType : 2; // nsIStandardURL::URLTYPE_xxx
uint32_t mMutable : 1; // nsIStandardURL::mutable
uint32_t mSupportsFileURL : 1; // QI to nsIFileURL?
uint32_t mCheckedIfHostA : 1; // If set to true, it means either that
// mDisplayHost has a been initialized, or
// that the hostname is not punycode
// global objects. don't use COMPtr as its destructor will cause a
// coredump if we leak it.