diff --git a/docshell/base/nsDefaultURIFixup.cpp b/docshell/base/nsDefaultURIFixup.cpp index 9976ffb37c3c..a4653b576be9 100644 --- a/docshell/base/nsDefaultURIFixup.cpp +++ b/docshell/base/nsDefaultURIFixup.cpp @@ -113,8 +113,11 @@ nsDefaultURIFixup::CreateFixupURI(const PRUnichar *aStringURI, PRUint32 aFixupFl // Just try to create an URL out of it NS_NewURI(aURI, uriString, nsnull); - if(*aURI) + if(*aURI) { + if (aFixupFlags & FIXUP_FLAGS_MAKE_ALTERNATE_URI) + MakeAlternateURI(*aURI); return NS_OK; + } // See if it is a keyword // Test whether keywords need to be fixed up @@ -152,10 +155,95 @@ nsDefaultURIFixup::CreateFixupURI(const PRUnichar *aStringURI, PRUint32 aFixupFl uriString.Assign(NS_LITERAL_STRING("http://") + uriString); } // end if checkprotocol - return NS_NewURI(aURI, uriString, nsnull); + nsresult rv = NS_NewURI(aURI, uriString, nsnull); + + // Did the caller want us to try an alternative URI? + // If so, attempt to fixup http://foo into http://www.foo.com + + if (aURI && aFixupFlags & FIXUP_FLAGS_MAKE_ALTERNATE_URI) { + MakeAlternateURI(*aURI); + } + + return rv; } +PRBool nsDefaultURIFixup::MakeAlternateURI(nsIURI *aURI) +{ + // Code only works for http. Not for any other protocol including https! + PRBool isHttp = PR_FALSE; + aURI->SchemeIs("http", &isHttp); + if (!isHttp) { + return PR_FALSE; + } + + // Security - URLs with user / password info should NOT be fixed up + nsXPIDLCString username; + nsXPIDLCString password; + aURI->GetUsername(getter_Copies(username)); + aURI->GetPassword(getter_Copies(password)); + if (username.Length() > 0 || password.Length() > 0) + { + return PR_FALSE; + } + + nsXPIDLCString host; + aURI->GetHost(getter_Copies(host)); + + nsCAutoString oldHost(host); + nsCAutoString newHost; + + // Count the dots + PRInt32 numDots = 0; + nsReadingIterator iter; + nsReadingIterator iterEnd; + oldHost.BeginReading(iter); + oldHost.EndReading(iterEnd); + while (iter != iterEnd) { + if (*iter == '.') + numDots++; + ++iter; + } + + // TODO: Defaulting to www.foo.com is a bit nasty. It should be a pref + // somewhere for people who'd prefer it to default to www.foo.org, + // www.foo.co.uk or whatever. + const char *prefix = "www."; + const char *suffix = ".com"; + + // Hardcoded to .com for the time being + if (numDots == 0) + { + newHost.Assign(prefix); + newHost.Append(oldHost); + newHost.Append(suffix); + } + else if (numDots == 1) + { + if (oldHost.EqualsIgnoreCase(prefix, nsCRT::strlen(prefix))) { + newHost.Assign(oldHost); + newHost.Append(suffix); + } + else { + newHost.Assign(prefix); + newHost.Append(oldHost); + } + } + else + { + // Do nothing + return PR_FALSE; + } + + if (newHost.IsEmpty()) { + return PR_FALSE; + } + + // Assign the new host string over the old one + aURI->SetHost(newHost.get()); + return PR_TRUE; +} + nsresult nsDefaultURIFixup::FileURIFixup(const PRUnichar* aStringURI, nsIURI** aURI) { diff --git a/docshell/base/nsDefaultURIFixup.h b/docshell/base/nsDefaultURIFixup.h index 9b6deea60ccf..81a030d7104c 100644 --- a/docshell/base/nsDefaultURIFixup.h +++ b/docshell/base/nsDefaultURIFixup.h @@ -48,7 +48,8 @@ private: nsresult ConvertFileToStringURI(nsString& aIn, nsCString& aOut); nsresult ConvertStringURIToFileCharset(nsString& aIn, nsCString& aOut); nsresult KeywordURIFixup(const PRUnichar* aStringURI, nsIURI** aURI); - PRBool PossiblyByteExpandedFileName(nsString& aIn); + PRBool PossiblyByteExpandedFileName(nsString& aIn); + PRBool MakeAlternateURI(nsIURI *aURI); nsCOMPtr mPrefs; }; diff --git a/docshell/base/nsIURIFixup.idl b/docshell/base/nsIURIFixup.idl index d8096438f5ac..fa00f540a7b8 100644 --- a/docshell/base/nsIURIFixup.idl +++ b/docshell/base/nsIURIFixup.idl @@ -40,6 +40,12 @@ interface nsIURIFixup : nsISupports */ const unsigned long FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP = 1; + /** + * Tell the fixup to make an alternate URI from the input URI, for example + * to turn foo into www.foo.com. + */ + const unsigned long FIXUP_FLAGS_MAKE_ALTERNATE_URI = 2; + /** * Converts the specified string into a URI, first attempting * to correct any errors in the syntax or other vagaries. Returns diff --git a/docshell/base/nsWebShell.cpp b/docshell/base/nsWebShell.cpp index 9446a8e430f5..15680d6509ce 100644 --- a/docshell/base/nsWebShell.cpp +++ b/docshell/base/nsWebShell.cpp @@ -84,7 +84,7 @@ typedef unsigned long HMTX; #include "nsplugin.h" //#include "nsPluginsCID.h" #include "nsIPluginManager.h" -#include "nsIPref.h" +#include "nsCDefaultURIFixup.h" #include "nsITimer.h" #include "nsITimerCallback.h" #include "nsIContent.h" @@ -944,107 +944,91 @@ nsresult nsWebShell::EndPageLoad(nsIWebProgress *aProgress, } return NS_OK; } - - nsXPIDLCString host; - rv = url->GetHost(getter_Copies(host)); - if (!host) { - return rv; - } - - CBufDescriptor buf((const char *)host, PR_TRUE, PL_strlen(host) + 1); - nsCAutoString hostStr(buf); - PRInt32 dotLoc = hostStr.FindChar('.'); - - nsXPIDLCString scheme; - url->GetScheme(getter_Copies(scheme)); - - PRUint32 schemeLen = PL_strlen((const char*)scheme); - CBufDescriptor schemeBuf((const char*)scheme, PR_TRUE, schemeLen+1, schemeLen); - nsCAutoString schemeStr(schemeBuf); - - // - // First try sending the request to a keyword server (if enabled)... - // - if(aStatus == NS_ERROR_UNKNOWN_HOST || - aStatus == NS_ERROR_CONNECTION_REFUSED || - aStatus == NS_ERROR_NET_TIMEOUT) + // Create the fixup object if necessary + if (!mURIFixup) { - PRBool keywordsEnabled = PR_FALSE; - - if(mPrefs) { - rv = mPrefs->GetBoolPref("keyword.enabled", &keywordsEnabled); - if (NS_FAILED(rv)) return rv; - } - - // we should only perform a keyword search under the following conditions: - // (0) Pref keyword.enabled is true - // (1) the url scheme is http (or https) - // (2) the url does not have a protocol scheme - // If we don't enforce such a policy, then we end up doing keyword searchs on urls - // we don't intend like imap, file, mailbox, etc. This could lead to a security - // problem where we send data to the keyword server that we shouldn't be. - // Someone needs to clean up keywords in general so we can determine on a per url basis - // if we want keywords enabled...this is just a bandaid... - if (keywordsEnabled && !schemeStr.IsEmpty() && - (schemeStr.Find("http") != 0)) { - keywordsEnabled = PR_FALSE; - } - - if(keywordsEnabled && (-1 == dotLoc)) { - // only send non-qualified hosts to the keyword server - nsAutoString keywordSpec(NS_LITERAL_STRING("keyword:")); - keywordSpec.Append(NS_ConvertUTF8toUCS2(host)); - - return LoadURI(keywordSpec.get(), // URI string - LOAD_FLAGS_NONE, // Load flags - nsnull, // Refering URI - nsnull, // Post data stream - nsnull); // Headers stream - } // end keywordsEnabled + mURIFixup = do_GetService(NS_URIFIXUP_CONTRACTID); } - // - // Next, try rewriting the URI using our www.*.com trick - // - if(aStatus == NS_ERROR_UNKNOWN_HOST) { - // Try our www.*.com trick. - nsCAutoString retryHost; + if (mURIFixup) + { + // + // Try and make an alternative URI from the old one + // + nsCOMPtr newURI; + nsXPIDLCString oldSpec; + url->GetSpec(getter_Copies(oldSpec)); + nsAutoString oldSpecW; oldSpecW.AssignWithConversion(oldSpec.get()); - if(schemeStr.Find("http") == 0) { - if(-1 == dotLoc) { - retryHost = "www."; - retryHost += hostStr; - retryHost += ".com"; - } else { - PRInt32 hostLen = hostStr.Length(); - if(((hostLen - dotLoc) == 3) || ((hostLen - dotLoc) == 4)) { - retryHost = "www."; - retryHost += hostStr; + // + // First try keyword fixup + // + if (aStatus == NS_ERROR_UNKNOWN_HOST || + aStatus == NS_ERROR_CONNECTION_REFUSED || + aStatus == NS_ERROR_NET_TIMEOUT) + { + mURIFixup->CreateFixupURI(oldSpecW.get(), + nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP, getter_AddRefs(newURI)); + } + + // + // Now try change the address, e.g. turn http://foo into http://www.foo.com + // + if (aStatus == NS_ERROR_UNKNOWN_HOST) + { + // Test if keyword lookup produced a new URI or not + PRBool doCreateAlternate = PR_TRUE; + if (newURI) + { + PRBool sameURI = PR_FALSE; + url->Equals(newURI, &sameURI); + if (!sameURI) + { + // Keyword lookup made a new URI so no need to try an + // alternate one. + doCreateAlternate = PR_FALSE; } } + if (doCreateAlternate) + { + newURI = nsnull; + mURIFixup->CreateFixupURI(oldSpecW.get(), + nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI, getter_AddRefs(newURI)); + } } - if(!retryHost.IsEmpty()) { - // This seems evil, since it is modifying the original URL - rv = url->SetHost(retryHost.get()); - if (NS_FAILED(rv)) return rv; - - rv = url->GetSpec(getter_Copies(host)); - if (NS_FAILED(rv)) return rv; + // + // Did we make a new URI that is different to the old one? If so load it. + // + if (newURI) + { + // Make sure the new URI is different from the old one, otherwise + // there's little point trying to load it again. + PRBool sameURI = PR_FALSE; + url->Equals(newURI, &sameURI); + if (!sameURI) + { + nsXPIDLCString newSpec; + newURI->GetSpec(getter_Copies(newSpec)); + nsAutoString newSpecW; newSpecW.AssignWithConversion(newSpec.get()); - // reload the url - return LoadURI(NS_ConvertASCIItoUCS2(host).get(), // URI string - LOAD_FLAGS_NONE, // Load flags - nsnull, // Refering URI - nsnull, // Post data stream - nsnull); // Header stream - } // retry + // This seems evil, since it is modifying the original URL + rv = url->SetSpec(newSpec.get()); + if (NS_FAILED(rv)) return rv; + + return LoadURI(newSpecW.get(), // URI string + LOAD_FLAGS_NONE, // Load flags + nsnull, // Refering URI + nsnull, // Post data stream + nsnull); // Headers stream + } + } } // - // Well, none of the URI rewriting tricks worked :-( + // Well, fixup didn't work :-( // It is time to throw an error dialog box, and be done with it... // @@ -1065,8 +1049,10 @@ nsresult nsWebShell::EndPageLoad(nsIWebProgress *aProgress, getter_Copies(messageStr)); if (NS_FAILED(rv)) return rv; + nsXPIDLCString host; + url->GetHost(getter_Copies(host)); if (host) { - PRUnichar *msg = nsTextFormatter::smprintf(messageStr, (const char*)host); + PRUnichar *msg = nsTextFormatter::smprintf(messageStr, host.get()); if (!msg) return NS_ERROR_OUT_OF_MEMORY; prompter->Alert(nsnull, msg); @@ -1098,6 +1084,8 @@ nsresult nsWebShell::EndPageLoad(nsIWebProgress *aProgress, if (NS_FAILED(rv)) return rv; // build up the host:port string. + nsXPIDLCString host; + url->GetHost(getter_Copies(host)); nsCAutoString combo(host); if (port > 0) { combo.Append(':'); @@ -1129,7 +1117,9 @@ nsresult nsWebShell::EndPageLoad(nsIWebProgress *aProgress, getter_Copies(messageStr)); if (NS_FAILED(rv)) return rv; - PRUnichar *msg = nsTextFormatter::smprintf(messageStr, (const char*)host); + nsXPIDLCString host; + url->GetHost(getter_Copies(host)); + PRUnichar *msg = nsTextFormatter::smprintf(messageStr, host.get()); if (!msg) return NS_ERROR_OUT_OF_MEMORY; prompter->Alert(nsnull, msg);