void nsMediaFragmentURIParser::Parse(nsACString& aRef) { // Create an array of possibly-invalid media fragments. nsTArray< std::pair<nsCString, nsCString> > fragments; nsCCharSeparatedTokenizer tokenizer(aRef, '&'); while (tokenizer.hasMoreTokens()) { const nsCSubstring& nv = tokenizer.nextToken(); int32_t index = nv.FindChar('='); if (index >= 0) { nsAutoCString name; nsAutoCString value; NS_UnescapeURL(StringHead(nv, index), esc_Ref | esc_AlwaysCopy, name); NS_UnescapeURL(Substring(nv, index + 1, nv.Length()), esc_Ref | esc_AlwaysCopy, value); fragments.AppendElement(make_pair(name, value)); } } // Parse the media fragment values. bool gotTemporal = false, gotSpatial = false; for (int i = fragments.Length() - 1 ; i >= 0 ; --i) { if (gotTemporal && gotSpatial) { // We've got one of each possible type. No need to look at the rest. break; } else if (!gotTemporal && fragments[i].first.EqualsLiteral("t")) { nsAutoString value = NS_ConvertUTF8toUTF16(fragments[i].second); gotTemporal = ParseNPT(nsDependentSubstring(value, 0)); } else if (!gotSpatial && fragments[i].first.EqualsLiteral("xywh")) { nsAutoString value = NS_ConvertUTF8toUTF16(fragments[i].second); gotSpatial = ParseXYWH(nsDependentSubstring(value, 0)); } } }
void nsHttpChannelAuthProvider::GetIdentityFromURI(uint32_t authFlags, nsHttpAuthIdentity &ident) { LOG(("nsHttpChannelAuthProvider::GetIdentityFromURI [this=%p channel=%p]\n", this, mAuthChannel)); nsAutoString userBuf; nsAutoString passBuf; // XXX i18n nsCAutoString buf; mURI->GetUsername(buf); if (!buf.IsEmpty()) { NS_UnescapeURL(buf); CopyASCIItoUTF16(buf, userBuf); mURI->GetPassword(buf); if (!buf.IsEmpty()) { NS_UnescapeURL(buf); CopyASCIItoUTF16(buf, passBuf); } } if (!userBuf.IsEmpty()) { SetIdent(ident, authFlags, (PRUnichar *) userBuf.get(), (PRUnichar *) passBuf.get()); } }
NS_IMETHODIMP nsFtpProtocolHandler::NewURI(const nsACString &aSpec, const char *aCharset, nsIURI *aBaseURI, nsIURI **result) { nsCAutoString spec(aSpec); char *fwdPtr = spec.BeginWriting(); // now unescape it... %xx reduced inline to resulting character PRInt32 len = NS_UnescapeURL(fwdPtr); // NS_UnescapeURL() modified spec's buffer, truncate to ensure // spec knows its new length. spec.Truncate(len); // return an error if we find a NUL, CR, or LF in the path if (spec.FindCharInSet(CRLF) >= 0 || spec.FindChar('\0') >= 0) return NS_ERROR_MALFORMED_URI; nsresult rv; nsCOMPtr<nsIStandardURL> url = do_CreateInstance(NS_STANDARDURL_CONTRACTID, &rv); if (NS_FAILED(rv)) return rv; rv = url->Init(nsIStandardURL::URLTYPE_AUTHORITY, 21, aSpec, aCharset, aBaseURI); if (NS_FAILED(rv)) return rv; return CallQueryInterface(url, result); }
NS_IMETHODIMP nsUTF8ConverterService::ConvertURISpecToUTF8(const nsACString &aSpec, const char *aCharset, nsACString &aUTF8Spec) { // assume UTF-8 if the spec contains unescaped non-ASCII characters. // No valid spec in Mozilla would break this assumption. if (!IsASCII(aSpec)) { aUTF8Spec = aSpec; return NS_OK; } aUTF8Spec.Truncate(); nsAutoCString unescapedSpec; // NS_UnescapeURL does not fill up unescapedSpec unless there's at least // one character to unescape. bool written = NS_UnescapeURL(PromiseFlatCString(aSpec).get(), aSpec.Length(), esc_OnlyNonASCII, unescapedSpec); if (!written) { aUTF8Spec = aSpec; return NS_OK; } // return if ASCII only or escaped UTF-8 if (IsASCII(unescapedSpec) || IsUTF8(unescapedSpec)) { aUTF8Spec = unescapedSpec; return NS_OK; } return ToUTF8(unescapedSpec, aCharset, true, aUTF8Spec); }
nsresult nsUrlClassifierUtils::CanonicalizeHostname(const nsACString & hostname, nsACString & _retval) { nsAutoCString unescaped; if (!NS_UnescapeURL(PromiseFlatCString(hostname).get(), PromiseFlatCString(hostname).Length(), 0, unescaped)) { unescaped.Assign(hostname); } nsAutoCString cleaned; CleanupHostname(unescaped, cleaned); nsAutoCString temp; ParseIPAddress(cleaned, temp); if (!temp.IsEmpty()) { cleaned.Assign(temp); } ToLowerCase(cleaned); SpecialEncode(cleaned, false, _retval); return NS_OK; }
nsresult SubstitutingProtocolHandler::ResolveURI(nsIURI *uri, nsACString &result) { nsresult rv; nsAutoCString host; nsAutoCString path; rv = uri->GetAsciiHost(host); if (NS_FAILED(rv)) return rv; rv = uri->GetPath(path); if (NS_FAILED(rv)) return rv; if (ResolveSpecialCases(host, path, result)) { return NS_OK; } nsCOMPtr<nsIURI> baseURI; rv = GetSubstitution(host, getter_AddRefs(baseURI)); if (NS_FAILED(rv)) return rv; // Unescape the path so we can perform some checks on it. nsCOMPtr<nsIURL> url = do_QueryInterface(uri); if (!url) { return NS_ERROR_MALFORMED_URI; } nsAutoCString unescapedPath; rv = url->GetFilePath(unescapedPath); if (NS_FAILED(rv)) return rv; NS_UnescapeURL(unescapedPath); if (unescapedPath.FindChar('\\') != -1) { return NS_ERROR_MALFORMED_URI; } // Some code relies on an empty path resolving to a file rather than a // directory. NS_ASSERTION(path.CharAt(0) == '/', "Path must begin with '/'"); if (path.Length() == 1) { rv = baseURI->GetSpec(result); } else { // Make sure we always resolve the path as file-relative to our target URI. path.InsertLiteral(".", 0); rv = baseURI->Resolve(path, result); } if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } if (MOZ_LOG_TEST(gResLog, LogLevel::Debug)) { nsAutoCString spec; uri->GetAsciiSpec(spec); MOZ_LOG(gResLog, LogLevel::Debug, ("%s\n -> %s\n", spec.get(), PromiseFlatCString(result).get())); } return rv; }
void TestUnescapeHelper(const char* in, const char* expected) { nsCString out, strIn(in), strExp(expected); nsUrlClassifierUtils utils; NS_UnescapeURL(strIn.get(), strIn.Length(), esc_AlwaysCopy, out); CheckEquals(strExp, out); }
NS_IMETHODIMP Location::GetHash(nsAString& aHash) { aHash.SetLength(0); nsCOMPtr<nsIURI> uri; nsresult rv = GetURI(getter_AddRefs(uri)); if (NS_FAILED(rv) || !uri) { return rv; } nsAutoCString ref; nsAutoString unicodeRef; rv = uri->GetRef(ref); if (nsContentUtils::GettersDecodeURLHash()) { if (NS_SUCCEEDED(rv)) { nsCOMPtr<nsITextToSubURI> textToSubURI( do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv)); if (NS_SUCCEEDED(rv)) { nsAutoCString charset; uri->GetOriginCharset(charset); rv = textToSubURI->UnEscapeURIForUI(charset, ref, unicodeRef); } if (NS_FAILED(rv)) { // Oh, well. No intl here! NS_UnescapeURL(ref); CopyASCIItoUTF16(ref, unicodeRef); rv = NS_OK; } } if (NS_SUCCEEDED(rv) && !unicodeRef.IsEmpty()) { aHash.Assign(char16_t('#')); aHash.Append(unicodeRef); } } else { // URL Hash should simply return the value of the Ref segment if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) { aHash.Assign(char16_t('#')); AppendUTF8toUTF16(ref, aHash); } } if (aHash == mCachedHash) { // Work around ShareThis stupidly polling location.hash every // 5ms all the time by handing out the same exact string buffer // we handed out last time. aHash = mCachedHash; } else { mCachedHash = aHash; } return rv; }
NS_IMETHODIMP nsIOService::UnescapeString(const nsACString &aStr, uint32_t aFlags, nsACString &aResult) { aResult.Truncate(); NS_UnescapeURL(aStr.BeginReading(), aStr.Length(), aFlags | esc_AlwaysCopy, aResult); return NS_OK; }
void nsMediaFragmentURIParser::Parse() { nsCCharSeparatedTokenizer tokenizer(mHash, '&'); while (tokenizer.hasMoreTokens()) { const nsCSubstring& nv = tokenizer.nextToken(); PRInt32 index = nv.FindChar('='); if (index >= 0) { nsCAutoString name; nsCAutoString value; NS_UnescapeURL(StringHead(nv, index), esc_Ref | esc_AlwaysCopy, name); NS_UnescapeURL(Substring(nv, index + 1, nv.Length()), esc_Ref | esc_AlwaysCopy, value); nsAutoString a = NS_ConvertUTF8toUTF16(name); nsAutoString b = NS_ConvertUTF8toUTF16(value); mFragments.AppendElement(Pair(a, b)); } } }
// Make sure Unescape from nsEncode.h's unescape does what the server does. void TestUnescape() { // test empty string TestUnescapeHelper("\0", "\0"); // Test docoding of all characters. nsCString allCharsEncoded, allCharsEncodedLowercase, allCharsAsString; for (PRInt32 i = 1; i < 256; ++i) { allCharsEncoded.Append('%'); allCharsEncoded.Append(int_to_hex_digit(i / 16)); allCharsEncoded.Append((int_to_hex_digit(i % 16))); allCharsEncodedLowercase.Append('%'); allCharsEncodedLowercase.Append(tolower(int_to_hex_digit(i / 16))); allCharsEncodedLowercase.Append(tolower(int_to_hex_digit(i % 16))); allCharsAsString.Append(static_cast<char>(i)); } nsUrlClassifierUtils utils; nsCString out; NS_UnescapeURL(allCharsEncoded.get(), allCharsEncoded.Length(), esc_AlwaysCopy, out); CheckEquals(allCharsAsString, out); out.Truncate(); NS_UnescapeURL(allCharsEncodedLowercase.get(), allCharsEncodedLowercase.Length(), esc_AlwaysCopy, out); CheckEquals(allCharsAsString, out); // Test %-related edge cases TestUnescapeHelper("%", "%"); TestUnescapeHelper("%xx", "%xx"); TestUnescapeHelper("%%", "%%"); TestUnescapeHelper("%%%", "%%%"); TestUnescapeHelper("%%%%", "%%%%"); TestUnescapeHelper("%1", "%1"); TestUnescapeHelper("%1z", "%1z"); TestUnescapeHelper("a%1z", "a%1z"); TestUnescapeHelper("abc%d%e%fg%hij%klmno%", "abc%d%e%fg%hij%klmno%"); // A few more tests TestUnescapeHelper("%25", "%"); TestUnescapeHelper("%25%32%35", "%25"); }
NS_IMETHODIMP nsLocation::GetHash(nsAString& aHash) { if (!CallerSubsumes()) return NS_ERROR_DOM_SECURITY_ERR; aHash.SetLength(0); nsCOMPtr<nsIURI> uri; nsresult rv = GetURI(getter_AddRefs(uri)); if (NS_FAILED(rv) || !uri) { return rv; } nsCAutoString ref; nsAutoString unicodeRef; rv = uri->GetRef(ref); if (NS_SUCCEEDED(rv)) { nsCOMPtr<nsITextToSubURI> textToSubURI( do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv)); if (NS_SUCCEEDED(rv)) { nsCAutoString charset; uri->GetOriginCharset(charset); rv = textToSubURI->UnEscapeURIForUI(charset, ref, unicodeRef); } if (NS_FAILED(rv)) { // Oh, well. No intl here! NS_UnescapeURL(ref); CopyASCIItoUTF16(ref, unicodeRef); rv = NS_OK; } } if (NS_SUCCEEDED(rv) && !unicodeRef.IsEmpty()) { aHash.Assign(PRUnichar('#')); aHash.Append(unicodeRef); } if (aHash == mCachedHash) { // Work around ShareThis stupidly polling location.hash every // 5ms all the time by handing out the same exact string buffer // we handed out last time. aHash = mCachedHash; } else { mCachedHash = aHash; } return rv; }
nsresult net_GetFileFromURLSpec(const nsACString &aURL, nsIFile **result) { // NOTE: See also the implementation in nsURLHelperOSX.cpp, // which is based on this. nsresult rv; nsCOMPtr<nsILocalFile> localFile; rv = NS_NewNativeLocalFile(EmptyCString(), PR_TRUE, getter_AddRefs(localFile)); if (NS_FAILED(rv)) return rv; nsCAutoString directory, fileBaseName, fileExtension, path; rv = net_ParseFileURL(aURL, directory, fileBaseName, fileExtension); if (NS_FAILED(rv)) return rv; if (!directory.IsEmpty()) NS_EscapeURL(directory, esc_Directory|esc_AlwaysCopy, path); if (!fileBaseName.IsEmpty()) NS_EscapeURL(fileBaseName, esc_FileBaseName|esc_AlwaysCopy, path); if (!fileExtension.IsEmpty()) { path += '.'; NS_EscapeURL(fileExtension, esc_FileExtension|esc_AlwaysCopy, path); } NS_UnescapeURL(path); if (path.Length() != strlen(path.get())) return NS_ERROR_FILE_INVALID_PATH; if (IsUTF8(path)) { // speed up the start-up where UTF-8 is the native charset // (e.g. on recent Linux distributions) if (NS_IsNativeUTF8()) rv = localFile->InitWithNativePath(path); else rv = localFile->InitWithPath(NS_ConvertUTF8toUTF16(path)); // XXX In rare cases, a valid UTF-8 string can be valid as a native // encoding (e.g. 0xC5 0x83 is valid both as UTF-8 and Windows-125x). // However, the chance is very low that a meaningful word in a legacy // encoding is valid as UTF-8. } else // if path is not in UTF-8, assume it is encoded in the native charset rv = localFile->InitWithNativePath(path); if (NS_FAILED(rv)) return rv; NS_ADDREF(*result = localFile); return NS_OK; }
void URL::GetHash(nsString& aHash) const { aHash.Truncate(); nsAutoCString ref; nsresult rv = mURI->GetRef(ref); if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) { NS_UnescapeURL(ref); // XXX may result in random non-ASCII bytes! aHash.Assign(PRUnichar('#')); AppendUTF8toUTF16(ref, aHash); } }
NS_IMETHODIMP nsResProtocolHandler::ResolveURI(nsIURI *uri, nsACString &result) { nsresult rv; nsCOMPtr<nsIURL> url(do_QueryInterface(uri)); if (!url) return NS_NOINTERFACE; nsCAutoString host; nsCAutoString path; rv = uri->GetAsciiHost(host); if (NS_FAILED(rv)) return rv; rv = uri->GetPath(path); if (NS_FAILED(rv)) return rv; nsCAutoString filepath; url->GetFilePath(filepath); // Don't misinterpret the filepath as an absolute URI. if (filepath.FindChar(':') != -1) return NS_ERROR_MALFORMED_URI; NS_UnescapeURL(filepath); if (filepath.FindChar('\\') != -1) return NS_ERROR_MALFORMED_URI; const char *p = path.get() + 1; // path always starts with a slash NS_ASSERTION(*(p-1) == '/', "Path did not begin with a slash!"); if (*p == '/') return NS_ERROR_MALFORMED_URI; nsCOMPtr<nsIURI> baseURI; rv = GetSubstitution(host, getter_AddRefs(baseURI)); if (NS_FAILED(rv)) return rv; rv = baseURI->Resolve(nsDependentCString(p, path.Length()-1), result); #if defined(PR_LOGGING) if (PR_LOG_TEST(gResLog, PR_LOG_DEBUG)) { nsCAutoString spec; uri->GetAsciiSpec(spec); LOG(("%s\n -> %s\n", spec.get(), PromiseFlatCString(result).get())); } #endif return rv; }
nsresult nsJARChannel::EnsureJarInput(PRBool blocking) { LOG(("nsJARChannel::EnsureJarInput [this=%x %s]\n", this, mSpec.get())); nsresult rv; nsCOMPtr<nsIURI> uri; rv = mJarURI->GetJARFile(getter_AddRefs(mJarBaseURI)); if (NS_FAILED(rv)) return rv; rv = mJarURI->GetJAREntry(mJarEntry); if (NS_FAILED(rv)) return rv; // The name of the JAR entry must not contain URL-escaped characters: // we're moving from URL domain to a filename domain here. nsStandardURL // does basic escaping by default, which breaks reading zipped files which // have e.g. spaces in their filenames. NS_UnescapeURL(mJarEntry); // try to get a nsIFile directly from the url, which will often succeed. { nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(mJarBaseURI); if (fileURL) fileURL->GetFile(getter_AddRefs(mJarFile)); } if (mJarFile) { mIsUnsafe = PR_FALSE; // NOTE: we do not need to deal with mSecurityInfo here, // because we're loading from a local file rv = CreateJarInput(gJarHandler->JarCache()); } else if (blocking) { NS_NOTREACHED("need sync downloader"); rv = NS_ERROR_NOT_IMPLEMENTED; } else { // kick off an async download of the base URI... rv = NS_NewDownloader(getter_AddRefs(mDownloader), this); if (NS_SUCCEEDED(rv)) rv = NS_OpenURI(mDownloader, nsnull, mJarBaseURI, nsnull, mLoadGroup, mCallbacks, mLoadFlags & ~(LOAD_DOCUMENT_URI | LOAD_CALL_CONTENT_SNIFFERS)); } return rv; }
void URLMainThread::GetHash(nsAString& aHash, ErrorResult& aRv) const { aHash.Truncate(); nsAutoCString ref; nsresult rv = mURI->GetRef(ref); if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) { aHash.Assign(char16_t('#')); if (nsContentUtils::GettersDecodeURLHash()) { NS_UnescapeURL(ref); // XXX may result in random non-ASCII bytes! } AppendUTF8toUTF16(ref, aHash); } }
nsresult SubstitutingProtocolHandler::ResolveURI(nsIURI *uri, nsACString &result) { nsresult rv; nsAutoCString host; nsAutoCString path; rv = uri->GetAsciiHost(host); if (NS_FAILED(rv)) return rv; rv = uri->GetPath(path); if (NS_FAILED(rv)) return rv; if (ResolveSpecialCases(host, path, result)) { return NS_OK; } // Unescape the path so we can perform some checks on it. nsAutoCString unescapedPath(path); NS_UnescapeURL(unescapedPath); // Don't misinterpret the filepath as an absolute URI. if (unescapedPath.FindChar(':') != -1) return NS_ERROR_MALFORMED_URI; if (unescapedPath.FindChar('\\') != -1) return NS_ERROR_MALFORMED_URI; const char *p = path.get() + 1; // path always starts with a slash NS_ASSERTION(*(p-1) == '/', "Path did not begin with a slash!"); if (*p == '/') return NS_ERROR_MALFORMED_URI; nsCOMPtr<nsIURI> baseURI; rv = GetSubstitution(host, getter_AddRefs(baseURI)); if (NS_FAILED(rv)) return rv; rv = baseURI->Resolve(nsDependentCString(p, path.Length()-1), result); if (MOZ_LOG_TEST(gResLog, LogLevel::Debug)) { nsAutoCString spec; uri->GetAsciiSpec(spec); MOZ_LOG(gResLog, LogLevel::Debug, ("%s\n -> %s\n", spec.get(), PromiseFlatCString(result).get())); } return rv; }
static bool pathBeginsWithVolName(const nsACString& path, nsACString& firstPathComponent) { // Return whether the 1st path component in path (escaped) is equal to the name // of a mounted volume. Return the 1st path component (unescaped) in any case. // This needs to be done as quickly as possible, so we cache a list of volume names. // XXX Register an event handler to detect drives being mounted/unmounted? if (!gVolumeList) { gVolumeList = new nsTArray<nsCString>; if (!gVolumeList) { return false; // out of memory } } // Cache a list of volume names if (!gVolumeList->Length()) { OSErr err; ItemCount volumeIndex = 1; do { HFSUniStr255 volName; FSRef rootDirectory; err = ::FSGetVolumeInfo(0, volumeIndex, NULL, kFSVolInfoNone, NULL, &volName, &rootDirectory); if (err == noErr) { NS_ConvertUTF16toUTF8 volNameStr(Substring((PRUnichar *)volName.unicode, (PRUnichar *)volName.unicode + volName.length)); gVolumeList->AppendElement(volNameStr); volumeIndex++; } } while (err == noErr); } // Extract the first component of the path nsACString::const_iterator start; path.BeginReading(start); start.advance(1); // path begins with '/' nsACString::const_iterator directory_end; path.EndReading(directory_end); nsACString::const_iterator component_end(start); FindCharInReadable('/', component_end, directory_end); nsCAutoString flatComponent((Substring(start, component_end))); NS_UnescapeURL(flatComponent); PRInt32 foundIndex = gVolumeList->IndexOf(flatComponent); firstPathComponent = flatComponent; return (foundIndex != -1); }
// // FindURLFromNativeURL // // we are looking for a URL and couldn't find it using our internal // URL flavor, so look for it using the native URL flavor, // CF_INETURLSTRW (We don't handle CF_INETURLSTRA currently) // bool nsClipboard :: FindURLFromNativeURL ( IDataObject* inDataObject, UINT inIndex, void** outData, PRUint32* outDataLen ) { bool dataFound = false; void* tempOutData = nullptr; PRUint32 tempDataLen = 0; nsresult loadResult = GetNativeDataOffClipboard(inDataObject, inIndex, ::RegisterClipboardFormat(CFSTR_INETURLW), nullptr, &tempOutData, &tempDataLen); if ( NS_SUCCEEDED(loadResult) && tempOutData ) { nsDependentString urlString(static_cast<PRUnichar*>(tempOutData)); // the internal mozilla URL format, text/x-moz-url, contains // URL\ntitle. Since we don't actually have a title here, // just repeat the URL to fake it. *outData = ToNewUnicode(urlString + NS_LITERAL_STRING("\n") + urlString); *outDataLen = NS_strlen(static_cast<PRUnichar*>(*outData)) * sizeof(PRUnichar); nsMemory::Free(tempOutData); dataFound = true; } else { loadResult = GetNativeDataOffClipboard(inDataObject, inIndex, ::RegisterClipboardFormat(CFSTR_INETURLA), nullptr, &tempOutData, &tempDataLen); if ( NS_SUCCEEDED(loadResult) && tempOutData ) { // CFSTR_INETURLA is (currently) equal to CFSTR_SHELLURL which is equal to CF_TEXT // which is by definition ANSI encoded. nsCString urlUnescapedA; bool unescaped = NS_UnescapeURL(static_cast<char*>(tempOutData), tempDataLen, esc_OnlyNonASCII | esc_SkipControl, urlUnescapedA); nsString urlString; if (unescaped) NS_CopyNativeToUnicode(urlUnescapedA, urlString); else NS_CopyNativeToUnicode(nsDependentCString(static_cast<char*>(tempOutData), tempDataLen), urlString); // the internal mozilla URL format, text/x-moz-url, contains // URL\ntitle. Since we don't actually have a title here, // just repeat the URL to fake it. *outData = ToNewUnicode(urlString + NS_LITERAL_STRING("\n") + urlString); *outDataLen = NS_strlen(static_cast<PRUnichar*>(*outData)) * sizeof(PRUnichar); nsMemory::Free(tempOutData); dataFound = true; } } return dataFound; } // FindURLFromNativeURL
nsresult nsUrlClassifierUtils::CanonicalizePath(const nsACString & path, nsACString & _retval) { _retval.Truncate(); nsAutoCString decodedPath(path); nsAutoCString temp; while (NS_UnescapeURL(decodedPath.get(), decodedPath.Length(), 0, temp)) { decodedPath.Assign(temp); temp.Truncate(); } SpecialEncode(decodedPath, true, _retval); // XXX: lowercase the path? return NS_OK; }
NS_IMETHODIMP nsTextToSubURI::UnEscapeURIForUI(const nsACString & aCharset, const nsACString &aURIFragment, nsAString &_retval) { nsAutoCString unescapedSpec; // skip control octets (0x00 - 0x1f and 0x7f) when unescaping NS_UnescapeURL(PromiseFlatCString(aURIFragment), esc_SkipControl | esc_AlwaysCopy, unescapedSpec); // in case of failure, return escaped URI // Test for != NS_OK rather than NS_FAILED, because incomplete multi-byte // sequences are also considered failure in this context if (convertURItoUnicode( PromiseFlatCString(aCharset), unescapedSpec, true, _retval) != NS_OK) // assume UTF-8 instead of ASCII because hostname (IDN) may be in UTF-8 CopyUTF8toUTF16(aURIFragment, _retval); return NS_OK; }
NS_IMETHODIMP nsLocation::GetHash(nsAString& aHash) { aHash.SetLength(0); nsCOMPtr<nsIURI> uri; nsresult rv = GetURI(getter_AddRefs(uri)); nsCOMPtr<nsIURL> url(do_QueryInterface(uri)); if (url) { nsCAutoString ref; nsAutoString unicodeRef; rv = url->GetRef(ref); if (NS_SUCCEEDED(rv)) { nsCOMPtr<nsITextToSubURI> textToSubURI( do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv)); if (NS_SUCCEEDED(rv)) { nsCAutoString charset; url->GetOriginCharset(charset); rv = textToSubURI->UnEscapeURIForUI(charset, ref, unicodeRef); } if (NS_FAILED(rv)) { // Oh, well. No intl here! NS_UnescapeURL(ref); CopyASCIItoUTF16(ref, unicodeRef); rv = NS_OK; } } if (NS_SUCCEEDED(rv) && !unicodeRef.IsEmpty()) { aHash.Assign(PRUnichar('#')); aHash.Append(unicodeRef); } } return rv; }
void Link::GetHash(nsAString &_hash, ErrorResult& aError) { _hash.Truncate(); nsCOMPtr<nsIURI> uri(GetURI()); if (!uri) { // Do not throw! Not having a valid URI should result in an empty // string. return; } nsAutoCString ref; nsresult rv = uri->GetRef(ref); if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) { NS_UnescapeURL(ref); // XXX may result in random non-ASCII bytes! _hash.Assign(char16_t('#')); AppendUTF8toUTF16(ref, _hash); } }
NS_IMETHODIMP nsTextToSubURI::UnEscapeNonAsciiURI(const nsACString & aCharset, const nsACString & aURIFragment, nsAString &_retval) { nsAutoCString unescapedSpec; NS_UnescapeURL(PromiseFlatCString(aURIFragment), esc_AlwaysCopy | esc_OnlyNonASCII, unescapedSpec); // leave the URI as it is if it's not UTF-8 and aCharset is not a ASCII // superset since converting "http:" with such an encoding is always a bad // idea. if (!IsUTF8(unescapedSpec) && (aCharset.LowerCaseEqualsLiteral("utf-16") || aCharset.LowerCaseEqualsLiteral("utf-16be") || aCharset.LowerCaseEqualsLiteral("utf-16le") || aCharset.LowerCaseEqualsLiteral("utf-7") || aCharset.LowerCaseEqualsLiteral("x-imap4-modified-utf7"))){ CopyASCIItoUTF16(aURIFragment, _retval); return NS_OK; } return convertURItoUnicode(PromiseFlatCString(aCharset), unescapedSpec, true, _retval); }
nsresult net_GetFileFromURLSpec(const nsACString &aURL, nsIFile **result) { nsresult rv; nsCOMPtr<nsIFile> localFile( do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv)); if (NS_FAILED(rv)) { NS_ERROR("Only nsIFile supported right now"); return rv; } localFile->SetFollowLinks(true); const nsACString *specPtr; nsAutoCString buf; if (net_NormalizeFileURL(aURL, buf)) specPtr = &buf; else specPtr = &aURL; nsAutoCString directory, fileBaseName, fileExtension; rv = net_ParseFileURL(*specPtr, directory, fileBaseName, fileExtension); if (NS_FAILED(rv)) return rv; nsAutoCString path; if (!directory.IsEmpty()) { NS_EscapeURL(directory, esc_Directory|esc_AlwaysCopy, path); if (path.Length() > 2 && path.CharAt(2) == '|') path.SetCharAt(':', 2); path.ReplaceChar('/', '\\'); } if (!fileBaseName.IsEmpty()) NS_EscapeURL(fileBaseName, esc_FileBaseName|esc_AlwaysCopy, path); if (!fileExtension.IsEmpty()) { path += '.'; NS_EscapeURL(fileExtension, esc_FileExtension|esc_AlwaysCopy, path); } NS_UnescapeURL(path); if (path.Length() != strlen(path.get())) return NS_ERROR_FILE_INVALID_PATH; // remove leading '\' if (path.CharAt(0) == '\\') path.Cut(0, 1); if (IsUTF8(path)) rv = localFile->InitWithPath(NS_ConvertUTF8toUTF16(path)); // XXX In rare cases, a valid UTF-8 string can be valid as a native // encoding (e.g. 0xC5 0x83 is valid both as UTF-8 and Windows-125x). // However, the chance is very low that a meaningful word in a legacy // encoding is valid as UTF-8. else // if path is not in UTF-8, assume it is encoded in the native charset rv = localFile->InitWithNativePath(path); if (NS_FAILED(rv)) return rv; NS_ADDREF(*result = localFile); return NS_OK; }
nsresult nsDataChannel::OpenContentStream(PRBool async, nsIInputStream **result, nsIChannel** channel) { NS_ENSURE_TRUE(URI(), NS_ERROR_NOT_INITIALIZED); nsresult rv; nsCAutoString spec; rv = URI()->GetAsciiSpec(spec); if (NS_FAILED(rv)) return rv; nsCString contentType, contentCharset, dataBuffer; PRBool lBase64; rv = nsDataHandler::ParseURI(spec, contentType, contentCharset, lBase64, dataBuffer); NS_UnescapeURL(dataBuffer); if (lBase64) { // Don't allow spaces in base64-encoded content. This is only // relevant for escaped spaces; other spaces are stripped in // NewURI. dataBuffer.StripWhitespace(); } nsCOMPtr<nsIInputStream> bufInStream; nsCOMPtr<nsIOutputStream> bufOutStream; // create an unbounded pipe. rv = NS_NewPipe(getter_AddRefs(bufInStream), getter_AddRefs(bufOutStream), nsIOService::gDefaultSegmentSize, PR_UINT32_MAX, async, PR_TRUE); if (NS_FAILED(rv)) return rv; PRUint32 contentLen; if (lBase64) { const PRUint32 dataLen = dataBuffer.Length(); PRInt32 resultLen = 0; if (dataLen >= 1 && dataBuffer[dataLen-1] == '=') { if (dataLen >= 2 && dataBuffer[dataLen-2] == '=') resultLen = dataLen-2; else resultLen = dataLen-1; } else { resultLen = dataLen; } resultLen = ((resultLen * 3) / 4); // XXX PL_Base64Decode will return a null pointer for decoding // errors. Since those are more likely than out-of-memory, // should we return NS_ERROR_MALFORMED_URI instead? char * decodedData = PL_Base64Decode(dataBuffer.get(), dataLen, nsnull); if (!decodedData) { return NS_ERROR_OUT_OF_MEMORY; } rv = bufOutStream->Write(decodedData, resultLen, &contentLen); PR_Free(decodedData); } else { rv = bufOutStream->Write(dataBuffer.get(), dataBuffer.Length(), &contentLen); } if (NS_FAILED(rv)) return rv; SetContentType(contentType); SetContentCharset(contentCharset); SetContentLength64(contentLen); NS_ADDREF(*result = bufInStream); return NS_OK; }
nsresult net_GetFileFromURLSpec(const nsACString &aURL, nsIFile **result) { // NOTE: See also the implementation in nsURLHelperUnix.cpp // This matches it except for the HFS path handling and file // system charset conversion. nsresult rv; nsCOMPtr<nsILocalFile> localFile; rv = NS_NewNativeLocalFile(EmptyCString(), PR_TRUE, getter_AddRefs(localFile)); if (NS_FAILED(rv)) return rv; nsCAutoString directory, fileBaseName, fileExtension, path; PRBool bHFSPath = PR_FALSE; rv = net_ParseFileURL(aURL, directory, fileBaseName, fileExtension); if (NS_FAILED(rv)) return rv; if (!directory.IsEmpty()) { NS_EscapeURL(directory, esc_Directory|esc_AlwaysCopy, path); // The canonical form of file URLs on OSX use POSIX paths: // file:///path-name. // But, we still encounter file URLs that use HFS paths: // file:///volume-name/path-name // Determine that here and normalize HFS paths to POSIX. nsCAutoString possibleVolName; if (pathBeginsWithVolName(directory, possibleVolName)) { // Though we know it begins with a volume name, it could still // be a valid POSIX path if the boot drive is named "Mac HD" // and there is a directory "Mac HD" at its root. If such a // directory doesn't exist, we'll assume this is an HFS path. FSRef testRef; possibleVolName.Insert("/", 0); if (::FSPathMakeRef((UInt8*)possibleVolName.get(), &testRef, nsnull) != noErr) bHFSPath = PR_TRUE; } if (bHFSPath) { // "%2F"s need to become slashes, while all other slashes need to // become colons. If we start out by changing "%2F"s to colons, we // can reply on SwapSlashColon() to do what we need path.ReplaceSubstring("%2F", ":"); path.Cut(0, 1); // directory begins with '/' SwapSlashColon((char *)path.get()); // At this point, path is an HFS path made using the same // algorithm as nsURLHelperMac. We'll convert to POSIX below. } } if (!fileBaseName.IsEmpty()) NS_EscapeURL(fileBaseName, esc_FileBaseName|esc_AlwaysCopy, path); if (!fileExtension.IsEmpty()) { path += '.'; NS_EscapeURL(fileExtension, esc_FileExtension|esc_AlwaysCopy, path); } NS_UnescapeURL(path); if (path.Length() != strlen(path.get())) return NS_ERROR_FILE_INVALID_PATH; if (bHFSPath) convertHFSPathtoPOSIX(path, path); // assuming path is encoded in the native charset rv = localFile->InitWithNativePath(path); if (NS_FAILED(rv)) return rv; NS_ADDREF(*result = localFile); return NS_OK; }
void nsReferencedElement::Reset(nsIContent* aFromContent, nsIURI* aURI, bool aWatch, bool aReferenceImage) { NS_ABORT_IF_FALSE(aFromContent, "Reset() expects non-null content pointer"); Unlink(); if (!aURI) return; nsCAutoString refPart; aURI->GetRef(refPart); // Unescape %-escapes in the reference. The result will be in the // origin charset of the URL, hopefully... NS_UnescapeURL(refPart); nsCAutoString charset; aURI->GetOriginCharset(charset); nsAutoString ref; nsresult rv = nsContentUtils::ConvertStringFromCharset(charset, refPart, ref); if (NS_FAILED(rv)) { CopyUTF8toUTF16(refPart, ref); } if (ref.IsEmpty()) return; // Get the current document nsIDocument *doc = aFromContent->GetCurrentDoc(); if (!doc) return; nsIContent* bindingParent = aFromContent->GetBindingParent(); if (bindingParent) { nsXBLBinding* binding = doc->BindingManager()->GetBinding(bindingParent); if (binding) { bool isEqualExceptRef; rv = aURI->EqualsExceptRef(binding->PrototypeBinding()->DocURI(), &isEqualExceptRef); if (NS_SUCCEEDED(rv) && isEqualExceptRef) { // XXX sXBL/XBL2 issue // Our content is an anonymous XBL element from a binding inside the // same document that the referenced URI points to. In order to avoid // the risk of ID collisions we restrict ourselves to anonymous // elements from this binding; specifically, URIs that are relative to // the binding document should resolve to the copy of the target // element that has been inserted into the bound document. // If the URI points to a different document we don't need this // restriction. nsINodeList* anonymousChildren = doc->BindingManager()->GetAnonymousNodesFor(bindingParent); if (anonymousChildren) { PRUint32 length; anonymousChildren->GetLength(&length); for (PRUint32 i = 0; i < length && !mElement; ++i) { mElement = nsContentUtils::MatchElementId(anonymousChildren->GetNodeAt(i), ref); } } // We don't have watching working yet for XBL, so bail out here. return; } } } bool isEqualExceptRef; rv = aURI->EqualsExceptRef(doc->GetDocumentURI(), &isEqualExceptRef); if (NS_FAILED(rv) || !isEqualExceptRef) { nsRefPtr<nsIDocument::ExternalResourceLoad> load; doc = doc->RequestExternalResource(aURI, aFromContent, getter_AddRefs(load)); if (!doc) { if (!load || !aWatch) { // Nothing will ever happen here return; } DocumentLoadNotification* observer = new DocumentLoadNotification(this, ref); mPendingNotification = observer; if (observer) { load->AddObserver(observer); } // Keep going so we set up our watching stuff a bit } } if (aWatch) { nsCOMPtr<nsIAtom> atom = do_GetAtom(ref); if (!atom) return; atom.swap(mWatchID); } mReferencingImage = aReferenceImage; HaveNewDocument(doc, aWatch, ref); }
PRemoteOpenFileParent* NeckoParent::AllocPRemoteOpenFileParent(const URIParams& aURI, const OptionalURIParams& aAppURI) { nsCOMPtr<nsIURI> uri = DeserializeURI(aURI); nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(uri); if (!fileURL) { return nullptr; } // security checks if (UsingNeckoIPCSecurity()) { nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID); if (!appsService) { return nullptr; } bool haveValidBrowser = false; bool hasManage = false; nsCOMPtr<mozIApplication> mozApp; for (uint32_t i = 0; i < Manager()->ManagedPBrowserParent().Length(); i++) { nsRefPtr<TabParent> tabParent = static_cast<TabParent*>(Manager()->ManagedPBrowserParent()[i]); uint32_t appId = tabParent->OwnOrContainingAppId(); nsresult rv = appsService->GetAppByLocalId(appId, getter_AddRefs(mozApp)); if (NS_FAILED(rv) || !mozApp) { continue; } hasManage = false; rv = mozApp->HasPermission("webapps-manage", &hasManage); if (NS_FAILED(rv)) { continue; } haveValidBrowser = true; break; } if (!haveValidBrowser) { return nullptr; } nsAutoCString requestedPath; fileURL->GetPath(requestedPath); NS_UnescapeURL(requestedPath); // Check if we load the whitelisted app uri for the neterror page. bool netErrorWhiteList = false; nsCOMPtr<nsIURI> appUri = DeserializeURI(aAppURI); if (appUri) { nsAdoptingString netErrorURI; netErrorURI = Preferences::GetString("b2g.neterror.url"); if (netErrorURI) { nsAutoCString spec; appUri->GetSpec(spec); netErrorWhiteList = spec.Equals(NS_ConvertUTF16toUTF8(netErrorURI).get()); } } if (hasManage || netErrorWhiteList) { // webapps-manage permission means allow reading any application.zip file // in either the regular webapps directory, or the core apps directory (if // we're using one). NS_NAMED_LITERAL_CSTRING(appzip, "/application.zip"); nsAutoCString pathEnd; requestedPath.Right(pathEnd, appzip.Length()); if (!pathEnd.Equals(appzip)) { return nullptr; } nsAutoCString pathStart; requestedPath.Left(pathStart, mWebAppsBasePath.Length()); if (!pathStart.Equals(mWebAppsBasePath)) { if (mCoreAppsBasePath.IsEmpty()) { return nullptr; } requestedPath.Left(pathStart, mCoreAppsBasePath.Length()); if (!pathStart.Equals(mCoreAppsBasePath)) { return nullptr; } } // Finally: make sure there are no "../" in URI. // Note: not checking for symlinks (would cause I/O for each path // component). So it's up to us to avoid creating symlinks that could // provide attack vectors. if (PL_strnstr(requestedPath.BeginReading(), "/../", requestedPath.Length())) { printf_stderr("NeckoParent::AllocPRemoteOpenFile: " "FATAL error: requested file URI '%s' contains '/../' " "KILLING CHILD PROCESS\n", requestedPath.get()); return nullptr; } } else { // regular packaged apps can only access their own application.zip file nsAutoString basePath; nsresult rv = mozApp->GetBasePath(basePath); if (NS_FAILED(rv)) { return nullptr; } nsAutoString uuid; rv = mozApp->GetId(uuid); if (NS_FAILED(rv)) { return nullptr; } nsPrintfCString mustMatch("%s/%s/application.zip", NS_LossyConvertUTF16toASCII(basePath).get(), NS_LossyConvertUTF16toASCII(uuid).get()); if (!requestedPath.Equals(mustMatch)) { printf_stderr("NeckoParent::AllocPRemoteOpenFile: " "FATAL error: app without webapps-manage permission is " "requesting file '%s' but is only allowed to open its " "own application.zip at %s: KILLING CHILD PROCESS\n", requestedPath.get(), mustMatch.get()); return nullptr; } } } RemoteOpenFileParent* parent = new RemoteOpenFileParent(fileURL); return parent; }