Back to index

lightning-sunbird  0.9+nobinonly
nsDefaultURIFixup.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is the Mozilla browser.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications, Inc.
00020  * Portions created by the Initial Developer are Copyright (C) 1999
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Adam Lock <adamlock@netscape.com>
00025  *   Jeff Walden <jwalden+code@mit.edu>
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 #include "nsString.h"
00042 #include "nsReadableUtils.h"
00043 #include "nsNetUtil.h"
00044 #include "nsEscape.h"
00045 #include "nsCRT.h"
00046 
00047 #include "nsIPrefService.h"
00048 #include "nsIPrefLocalizedString.h"
00049 #include "nsIPlatformCharset.h"
00050 #include "nsILocalFile.h"
00051 
00052 #include "nsIURIFixup.h"
00053 #include "nsDefaultURIFixup.h"
00054 
00055 /* Implementation file */
00056 NS_IMPL_ISUPPORTS2(nsDefaultURIFixup, nsIURIFixup, nsIURIFixup_MOZILLA_1_8_BRANCH)
00057 
00058 nsDefaultURIFixup::nsDefaultURIFixup()
00059 {
00060   /* member initializers and constructor code */
00061 
00062   // Try and get the pref service
00063   mPrefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID);
00064 }
00065 
00066 
00067 nsDefaultURIFixup::~nsDefaultURIFixup()
00068 {
00069   /* destructor code */
00070 }
00071 
00072 /* nsIURI createExposableURI (in nsIRUI aURI); */
00073 NS_IMETHODIMP
00074 nsDefaultURIFixup::CreateExposableURI(nsIURI *aURI, nsIURI **aReturn)
00075 {
00076     // NOTE: Make sure that this function DOES NOT change which
00077     // principal ought to correspond to aURI.
00078     
00079     NS_ENSURE_ARG_POINTER(aURI);
00080     NS_ENSURE_ARG_POINTER(aReturn);
00081 
00082     PRBool isWyciwyg = PR_FALSE;
00083     aURI->SchemeIs("wyciwyg", &isWyciwyg);
00084 
00085     nsCAutoString userPass;
00086     aURI->GetUserPass(userPass);
00087 
00088     // most of the time we can just AddRef and return
00089     if (!isWyciwyg && userPass.IsEmpty())
00090     {
00091         *aReturn = aURI;
00092         NS_ADDREF(*aReturn);
00093         return NS_OK;
00094     }
00095 
00096     // Rats, we have to massage the URI
00097     nsCOMPtr<nsIURI> uri;
00098     if (isWyciwyg)
00099     {
00100         nsCAutoString path;
00101         nsresult rv = aURI->GetPath(path);
00102         NS_ENSURE_SUCCESS(rv, rv);
00103 
00104         PRUint32 pathLength = path.Length();
00105         if (pathLength <= 2)
00106         {
00107             return NS_ERROR_FAILURE;
00108         }
00109 
00110         // Path is of the form "//123/http://foo/bar", with a variable number of digits.
00111         // To figure out where the "real" URL starts, search path for a '/', starting at 
00112         // the third character.
00113         PRInt32 slashIndex = path.FindChar('/', 2);
00114         if (slashIndex == kNotFound)
00115         {
00116             return NS_ERROR_FAILURE;
00117         }
00118 
00119         // Get the charset of the original URI so we can pass it to our fixed up URI.
00120         nsCAutoString charset;
00121         aURI->GetOriginCharset(charset);
00122 
00123         rv = NS_NewURI(getter_AddRefs(uri),
00124                    Substring(path, slashIndex + 1, pathLength - slashIndex - 1),
00125                    charset.get());
00126         NS_ENSURE_SUCCESS(rv, rv);
00127     }
00128     else
00129     {
00130         // clone the URI so zapping user:pass doesn't change the original
00131         nsresult rv = aURI->Clone(getter_AddRefs(uri));
00132         NS_ENSURE_SUCCESS(rv, rv);
00133     }
00134 
00135     // hide user:pass unless overridden by pref
00136     PRBool hideUserPass = PR_TRUE;
00137     if (mPrefBranch)
00138     {
00139         mPrefBranch->GetBoolPref("browser.fixup.hide_user_pass", &hideUserPass);
00140     }
00141     if (hideUserPass)
00142         uri->SetUserPass(EmptyCString());
00143 
00144     // return the fixed-up URI
00145     *aReturn = uri;
00146     NS_ADDREF(*aReturn);
00147     return NS_OK;
00148 }
00149 
00150 /* nsIURI createFixupURI (in nsAUTF8String aURIText, in unsigned long aFixupFlags); */
00151 NS_IMETHODIMP
00152 nsDefaultURIFixup::CreateFixupURI(const nsACString& aStringURI, PRUint32 aFixupFlags, nsIURI **aURI)
00153 {
00154     NS_ENSURE_ARG(!aStringURI.IsEmpty());
00155     NS_ENSURE_ARG_POINTER(aURI);
00156 
00157     nsresult rv;
00158     *aURI = nsnull;
00159 
00160     nsCAutoString uriString(aStringURI);
00161     uriString.Trim(" ");  // Cleanup the empty spaces that might be on each end.
00162 
00163     // Eliminate embedded newlines, which single-line text fields now allow:
00164     uriString.StripChars("\r\n");
00165 
00166     NS_ENSURE_TRUE(!uriString.IsEmpty(), NS_ERROR_FAILURE);
00167 
00168     nsCOMPtr<nsIIOService> ioService = do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
00169     NS_ENSURE_SUCCESS(rv, rv);
00170     nsCAutoString scheme;
00171     ioService->ExtractScheme(aStringURI, scheme);
00172     
00173     // View-source is a pseudo scheme. We're interested in fixing up the stuff
00174     // after it. The easiest way to do that is to call this method again with the
00175     // "view-source:" lopped off and then prepend it again afterwards.
00176 
00177     if (scheme.LowerCaseEqualsLiteral("view-source"))
00178     {
00179         nsCOMPtr<nsIURI> uri;
00180         PRUint32 newFixupFlags = aFixupFlags & ~FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
00181 
00182         rv =  CreateFixupURI(Substring(uriString,
00183                                        sizeof("view-source:") - 1,
00184                                        uriString.Length() -
00185                                          (sizeof("view-source:") - 1)),
00186                              newFixupFlags, getter_AddRefs(uri));
00187         if (NS_FAILED(rv))
00188             return NS_ERROR_FAILURE;
00189         nsCAutoString spec;
00190         uri->GetSpec(spec);
00191         uriString.Assign(NS_LITERAL_CSTRING("view-source:") + spec);
00192     }
00193     else {
00194         // Check for if it is a file URL
00195         FileURIFixup(uriString, aURI);
00196         if(*aURI)
00197             return NS_OK;
00198 
00199 #if defined(XP_WIN) || defined(XP_OS2)
00200         // Not a file URL, so translate '\' to '/' for convenience in the common protocols
00201         // e.g. catch
00202         //
00203         //   http:\\broken.com\address
00204         //   http:\\broken.com/blah
00205         //   broken.com\blah
00206         //
00207         // Code will also do partial fix up the following urls
00208         //
00209         //   http:\\broken.com\address/somewhere\image.jpg (stops at first forward slash)
00210         //   http:\\broken.com\blah?arg=somearg\foo.jpg (stops at question mark)
00211         //   http:\\broken.com#odd\ref (stops at hash)
00212         //  
00213         if (scheme.IsEmpty() ||
00214             scheme.LowerCaseEqualsLiteral("http") ||
00215             scheme.LowerCaseEqualsLiteral("https") ||
00216             scheme.LowerCaseEqualsLiteral("ftp"))
00217         {
00218             // Walk the string replacing backslashes with forward slashes until
00219             // the end is reached, or a question mark, or a hash, or a forward
00220             // slash. The forward slash test is to stop before trampling over
00221             // URIs which legitimately contain a mix of both forward and
00222             // backward slashes.
00223             nsCAutoString::iterator start;
00224             nsCAutoString::iterator end;
00225             uriString.BeginWriting(start);
00226             uriString.EndWriting(end);
00227             while (start != end) {
00228                 if (*start == '?' || *start == '#' || *start == '/')
00229                     break;
00230                 if (*start == '\\')
00231                     *start = '/';
00232                 ++start;
00233             }
00234         }
00235 #endif
00236     }
00237 
00238     // For these protocols, use system charset instead of the default UTF-8,
00239     // if the URI is non ASCII.
00240     PRBool bAsciiURI = IsASCII(uriString);
00241     PRBool bUseNonDefaultCharsetForURI =
00242                         !bAsciiURI &&
00243                         (scheme.IsEmpty() ||
00244                          scheme.LowerCaseEqualsLiteral("http") ||
00245                          scheme.LowerCaseEqualsLiteral("https") ||
00246                          scheme.LowerCaseEqualsLiteral("ftp") ||
00247                          scheme.LowerCaseEqualsLiteral("file"));
00248 
00249     // Now we need to check whether "scheme" is something we don't
00250     // really know about.
00251     nsCOMPtr<nsIProtocolHandler> ourHandler, extHandler;
00252     
00253     ioService->GetProtocolHandler(scheme.get(), getter_AddRefs(ourHandler));
00254     extHandler = do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX"default");
00255     
00256     if (ourHandler != extHandler || !PossiblyHostPortUrl(uriString)) {
00257         // Just try to create an URL out of it
00258         rv = NS_NewURI(aURI, uriString,
00259                        bUseNonDefaultCharsetForURI ? GetCharsetForUrlBar() : nsnull);
00260 
00261         if (!*aURI && rv != NS_ERROR_MALFORMED_URI) {
00262             return rv;
00263         }
00264     }
00265     
00266     if (*aURI) {
00267         if (aFixupFlags & FIXUP_FLAGS_MAKE_ALTERNATE_URI)
00268             MakeAlternateURI(*aURI);
00269         return NS_OK;
00270     }
00271 
00272     // See if it is a keyword
00273     // Test whether keywords need to be fixed up
00274     PRBool fixupKeywords = PR_FALSE;
00275     if (aFixupFlags & FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP) {
00276         if (mPrefBranch)
00277         {
00278             NS_ENSURE_SUCCESS(mPrefBranch->GetBoolPref("keyword.enabled", &fixupKeywords), NS_ERROR_FAILURE);
00279         }
00280         if (fixupKeywords)
00281         {
00282             KeywordURIFixup(uriString, aURI);
00283             if(*aURI)
00284                 return NS_OK;
00285         }
00286     }
00287 
00288     // Prune duff protocol schemes
00289     //
00290     //   ://totallybroken.url.com
00291     //   //shorthand.url.com
00292     //
00293     if (StringBeginsWith(uriString, NS_LITERAL_CSTRING("://")))
00294     {
00295         uriString = StringTail(uriString, uriString.Length() - 3);
00296     }
00297     else if (StringBeginsWith(uriString, NS_LITERAL_CSTRING("//")))
00298     {
00299         uriString = StringTail(uriString, uriString.Length() - 2);
00300     }
00301 
00302     // Add ftp:// or http:// to front of url if it has no spec
00303     //
00304     // Should fix:
00305     //
00306     //   no-scheme.com
00307     //   ftp.no-scheme.com
00308     //   ftp4.no-scheme,com
00309     //   no-scheme.com/query?foo=http://www.foo.com
00310     //
00311     PRInt32 schemeDelim = uriString.Find("://",0);
00312     PRInt32 firstDelim = uriString.FindCharInSet("/:");
00313     if (schemeDelim <= 0 ||
00314         (firstDelim != -1 && schemeDelim > firstDelim)) {
00315         // find host name
00316         PRInt32 hostPos = uriString.FindCharInSet("/:?#");
00317         if (hostPos == -1) 
00318             hostPos = uriString.Length();
00319 
00320         // extract host name
00321         nsCAutoString hostSpec;
00322         uriString.Left(hostSpec, hostPos);
00323 
00324         // insert url spec corresponding to host name
00325         if (hostSpec.EqualsIgnoreCase("ftp", 3)) 
00326             uriString.Assign(NS_LITERAL_CSTRING("ftp://") + uriString);
00327         else 
00328             uriString.Assign(NS_LITERAL_CSTRING("http://") + uriString);
00329 
00330         // For ftp & http, we want to use system charset.
00331         if (!bAsciiURI)
00332           bUseNonDefaultCharsetForURI = PR_TRUE;
00333     } // end if checkprotocol
00334 
00335     rv = NS_NewURI(aURI, uriString, bUseNonDefaultCharsetForURI ? GetCharsetForUrlBar() : nsnull);
00336 
00337     // Did the caller want us to try an alternative URI?
00338     // If so, attempt to fixup http://foo into http://www.foo.com
00339 
00340     if (*aURI && aFixupFlags & FIXUP_FLAGS_MAKE_ALTERNATE_URI) {
00341         MakeAlternateURI(*aURI);
00342     }
00343 
00344     // If we still haven't been able to construct a valid URI, try to force a
00345     // keyword match.  This catches search strings with '.' or ':' in them.
00346     if (!*aURI && fixupKeywords)
00347     {
00348         KeywordToURI(aStringURI, aURI);
00349         if(*aURI)
00350             return NS_OK;
00351     }
00352 
00353     return rv;
00354 }
00355 
00356 static nsresult MangleKeywordIntoURI(const char *aKeyword, const char *aURL,
00357                                      nsCString& query)
00358 {
00359     query = (*aKeyword == '?') ? (aKeyword + 1) : aKeyword;
00360     query.Trim(" "); // pull leading/trailing spaces.
00361 
00362     // encode
00363     char * encQuery = nsEscape(query.get(), url_XPAlphas);
00364     if (!encQuery) return NS_ERROR_OUT_OF_MEMORY;
00365     query.Adopt(encQuery);
00366 
00367     // prepend the query with the keyword url
00368     // XXX this url should come from somewhere else
00369     query.Insert(aURL, 0);
00370     return NS_OK;
00371 }
00372 
00373 NS_IMETHODIMP nsDefaultURIFixup::KeywordToURI(const nsACString& aKeyword,
00374                                               nsIURI **aURI)
00375 {
00376     *aURI = nsnull;
00377     NS_ENSURE_STATE(mPrefBranch);
00378 
00379     nsXPIDLCString url;
00380     nsCOMPtr<nsIPrefLocalizedString> keywordURL;
00381     mPrefBranch->GetComplexValue("keyword.URL", 
00382                                  NS_GET_IID(nsIPrefLocalizedString),
00383                                  getter_AddRefs(keywordURL));
00384 
00385     if (keywordURL) {
00386         nsXPIDLString wurl;
00387         keywordURL->GetData(getter_Copies(wurl));
00388         CopyUTF16toUTF8(wurl, url);
00389     } else {
00390         // Fall back to a non-localized pref, for backwards compat
00391         mPrefBranch->GetCharPref("keyword.URL", getter_Copies(url));
00392     }
00393 
00394     // if we can't find a keyword.URL keywords won't work.
00395     if (url.IsEmpty())
00396         return NS_ERROR_NOT_AVAILABLE;
00397 
00398     nsCAutoString spec;
00399     nsresult rv = MangleKeywordIntoURI(PromiseFlatCString(aKeyword).get(),
00400                                        url.get(), spec);
00401     if (NS_FAILED(rv)) return rv;
00402 
00403     return NS_NewURI(aURI, spec);
00404 }
00405 
00406 PRBool nsDefaultURIFixup::MakeAlternateURI(nsIURI *aURI)
00407 {
00408     if (!mPrefBranch)
00409     {
00410         return PR_FALSE;
00411     }
00412     PRBool makeAlternate = PR_TRUE;
00413     mPrefBranch->GetBoolPref("browser.fixup.alternate.enabled", &makeAlternate);
00414     if (!makeAlternate)
00415     {
00416         return PR_FALSE;
00417     }
00418 
00419     // Code only works for http. Not for any other protocol including https!
00420     PRBool isHttp = PR_FALSE;
00421     aURI->SchemeIs("http", &isHttp);
00422     if (!isHttp) {
00423         return PR_FALSE;
00424     }
00425 
00426     // Security - URLs with user / password info should NOT be fixed up
00427     nsCAutoString userpass;
00428     aURI->GetUserPass(userpass);
00429     if (!userpass.IsEmpty()) {
00430         return PR_FALSE;
00431     }
00432 
00433     nsCAutoString oldHost;
00434     nsCAutoString newHost;
00435     aURI->GetHost(oldHost);
00436 
00437     // Count the dots
00438     PRInt32 numDots = 0;
00439     nsReadingIterator<char> iter;
00440     nsReadingIterator<char> iterEnd;
00441     oldHost.BeginReading(iter);
00442     oldHost.EndReading(iterEnd);
00443     while (iter != iterEnd) {
00444         if (*iter == '.')
00445             numDots++;
00446         ++iter;
00447     }
00448 
00449 
00450     nsresult rv;
00451 
00452     // Get the prefix and suffix to stick onto the new hostname. By default these
00453     // are www. & .com but they could be any other value, e.g. www. & .org
00454 
00455     nsCAutoString prefix("www.");
00456     nsXPIDLCString prefPrefix;
00457     rv = mPrefBranch->GetCharPref("browser.fixup.alternate.prefix", getter_Copies(prefPrefix));
00458     if (NS_SUCCEEDED(rv))
00459     {
00460         prefix.Assign(prefPrefix);
00461     }
00462 
00463     nsCAutoString suffix(".com");
00464     nsXPIDLCString prefSuffix;
00465     rv = mPrefBranch->GetCharPref("browser.fixup.alternate.suffix", getter_Copies(prefSuffix));
00466     if (NS_SUCCEEDED(rv))
00467     {
00468         suffix.Assign(prefSuffix);
00469     }
00470     
00471     if (numDots == 0)
00472     {
00473         newHost.Assign(prefix);
00474         newHost.Append(oldHost);
00475         newHost.Append(suffix);
00476     }
00477     else if (numDots == 1)
00478     {
00479         if (!prefix.IsEmpty() &&
00480                 oldHost.EqualsIgnoreCase(prefix.get(), prefix.Length())) {
00481             newHost.Assign(oldHost);
00482             newHost.Append(suffix);
00483         }
00484         else if (!suffix.IsEmpty()) {
00485             newHost.Assign(prefix);
00486             newHost.Append(oldHost);
00487         }
00488         else
00489         {
00490             // Do nothing
00491             return PR_FALSE;
00492         }
00493     }
00494     else
00495     {
00496         // Do nothing
00497         return PR_FALSE;
00498     }
00499 
00500     if (newHost.IsEmpty()) {
00501         return PR_FALSE;
00502     }
00503 
00504     // Assign the new host string over the old one
00505     aURI->SetHost(newHost);
00506     return PR_TRUE;
00507 }
00508 
00509 nsresult nsDefaultURIFixup::FileURIFixup(const nsACString& aStringURI, 
00510                                          nsIURI** aURI)
00511 {
00512     nsCAutoString uriSpecOut;
00513 
00514     nsresult rv = ConvertFileToStringURI(aStringURI, uriSpecOut);
00515     if (NS_SUCCEEDED(rv))
00516     {
00517         // if this is file url, uriSpecOut is already in FS charset
00518         if(NS_SUCCEEDED(NS_NewURI(aURI, uriSpecOut.get(), nsnull)))
00519             return NS_OK;
00520     } 
00521     return NS_ERROR_FAILURE;
00522 }
00523 
00524 nsresult nsDefaultURIFixup::ConvertFileToStringURI(const nsACString& aIn,
00525                                                    nsCString& aOut)
00526 {
00527     PRBool attemptFixup = PR_FALSE;
00528 
00529 #if defined(XP_WIN) || defined(XP_OS2)
00530     // Check for \ in the url-string or just a drive (PC)
00531     if(kNotFound != aIn.FindChar('\\') ||
00532        (aIn.Length() == 2 && (aIn.Last() == ':' || aIn.Last() == '|')))
00533     {
00534         attemptFixup = PR_TRUE;
00535     }
00536 #elif defined(XP_UNIX) || defined(XP_BEOS)
00537     // Check if it starts with / (UNIX)
00538     if(aIn.First() == '/')
00539     {
00540         attemptFixup = PR_TRUE;
00541     }
00542 #else
00543     // Do nothing (All others for now) 
00544 #endif
00545 
00546     if (attemptFixup)
00547     {
00548         // Test if this is a valid path by trying to create a local file
00549         // object. The URL of that is returned if successful.
00550 
00551         // NOTE: Please be sure to check that the call to NS_NewLocalFile
00552         //       rejects bad file paths when using this code on a new
00553         //       platform.
00554 
00555         nsCOMPtr<nsILocalFile> filePath;
00556         nsresult rv;
00557 
00558         // this is not the real fix but a temporary fix
00559         // in order to really fix the problem, we need to change the 
00560         // nsICmdLineService interface to use wstring to pass paramenters 
00561         // instead of string since path name and other argument could be
00562         // in non ascii.(see bug 87127) Since it is too risky to make interface change right
00563         // now, we decide not to do so now.
00564         // Therefore, the aIn we receive here maybe already in damage form
00565         // (e.g. treat every bytes as ISO-8859-1 and cast up to PRUnichar
00566         //  while the real data could be in file system charset )
00567         // we choice the following logic which will work for most of the case.
00568         // Case will still failed only if it meet ALL the following condiction:
00569         //    1. running on CJK, Russian, or Greek system, and 
00570         //    2. user type it from URL bar
00571         //    3. the file name contains character in the range of 
00572         //       U+00A1-U+00FF but encode as different code point in file
00573         //       system charset (e.g. ACP on window)- this is very rare case
00574         // We should remove this logic and convert to File system charset here
00575         // once we change nsICmdLineService to use wstring and ensure
00576         // all the Unicode data come in is correctly converted.
00577         // XXXbz nsICmdLineService doesn't hand back unicode, so in some cases
00578         // what we have is actually a "utf8" version of a "utf16" string that's
00579         // actually byte-expanded native-encoding data.  Someone upstream needs
00580         // to stop using AssignWithConversion and do things correctly.  See bug
00581         // 58866 for what happens if we remove this
00582         // PossiblyByteExpandedFileName check.
00583         NS_ConvertUTF8toUCS2 in(aIn);
00584         if (PossiblyByteExpandedFileName(in)) {
00585           // removes high byte
00586           rv = NS_NewNativeLocalFile(NS_LossyConvertUCS2toASCII(in), PR_FALSE, getter_AddRefs(filePath));
00587         }
00588         else {
00589           // input is unicode
00590           rv = NS_NewLocalFile(in, PR_FALSE, getter_AddRefs(filePath));
00591         }
00592 
00593         if (NS_SUCCEEDED(rv))
00594         {
00595             NS_GetURLSpecFromFile(filePath, aOut);
00596             return NS_OK;
00597         }
00598     }
00599 
00600     return NS_ERROR_FAILURE;
00601 }
00602 
00603 PRBool nsDefaultURIFixup::PossiblyHostPortUrl(const nsACString &aUrl)
00604 {
00605     // Oh dear, the protocol is invalid. Test if the protocol might
00606     // actually be a url without a protocol:
00607     //
00608     //   http://www.faqs.org/rfcs/rfc1738.html
00609     //   http://www.faqs.org/rfcs/rfc2396.html
00610     //
00611     // e.g. Anything of the form:
00612     //
00613     //   <hostname>:<port> or
00614     //   <hostname>:<port>/
00615     //
00616     // Where <hostname> is a string of alphanumeric characters and dashes
00617     // separated by dots.
00618     // and <port> is a 5 or less digits. This actually breaks the rfc2396
00619     // definition of a scheme which allows dots in schemes.
00620     //
00621     // Note:
00622     //   People expecting this to work with
00623     //   <user>:<password>@<host>:<port>/<url-path> will be disappointed!
00624     //
00625     // Note: Parser could be a lot tighter, tossing out silly hostnames
00626     //       such as those containing consecutive dots and so on.
00627 
00628     // Read the hostname which should of the form
00629     // [a-zA-Z0-9\-]+(\.[a-zA-Z0-9\-]+)*:
00630 
00631     nsACString::const_iterator iterBegin;
00632     nsACString::const_iterator iterEnd;
00633     aUrl.BeginReading(iterBegin);
00634     aUrl.EndReading(iterEnd);
00635     nsACString::const_iterator iter = iterBegin;
00636 
00637     while (iter != iterEnd)
00638     {
00639         PRUint32 chunkSize = 0;
00640         // Parse a chunk of the address
00641         while (iter != iterEnd &&
00642                (*iter == '-' ||
00643                 nsCRT::IsAsciiAlpha(*iter) ||
00644                 nsCRT::IsAsciiDigit(*iter)))
00645         {
00646             ++chunkSize;
00647             ++iter;
00648         }
00649         if (chunkSize == 0 || iter == iterEnd)
00650         {
00651             return PR_FALSE;
00652         }
00653         if (*iter == ':')
00654         {
00655             // Go onto checking the for the digits
00656             break;
00657         }
00658         if (*iter != '.')
00659         {
00660             // Whatever it is, it ain't a hostname!
00661             return PR_FALSE;
00662         }
00663         ++iter;
00664     }
00665     if (iter == iterEnd)
00666     {
00667         // No point continuing since there is no colon
00668         return PR_FALSE;
00669     }
00670     ++iter;
00671 
00672     // Count the number of digits after the colon and before the
00673     // next forward slash (or end of string)
00674 
00675     PRUint32 digitCount = 0;
00676     while (iter != iterEnd && digitCount <= 5)
00677     {
00678         if (nsCRT::IsAsciiDigit(*iter))
00679         {
00680             digitCount++;
00681         }
00682         else if (*iter == '/')
00683         {
00684             break;
00685         }
00686         else
00687         {
00688             // Whatever it is, it ain't a port!
00689             return PR_FALSE;
00690         }
00691         ++iter;
00692     }
00693     if (digitCount == 0 || digitCount > 5)
00694     {
00695         // No digits or more digits than a port would have.
00696         return PR_FALSE;
00697     }
00698 
00699     // Yes, it's possibly a host:port url
00700     return PR_TRUE;
00701 }
00702 
00703 PRBool nsDefaultURIFixup::PossiblyByteExpandedFileName(const nsAString& aIn)
00704 {
00705     // XXXXX HACK XXXXX : please don't copy this code.
00706     // There are cases where aIn contains the locale byte chars padded to short
00707     // (thus the name "ByteExpanded"); whereas other cases 
00708     // have proper Unicode code points.
00709     // This is a temporary fix.  Please refer to 58866, 86948
00710 
00711     nsReadingIterator<PRUnichar> iter;
00712     nsReadingIterator<PRUnichar> iterEnd;
00713     aIn.BeginReading(iter);
00714     aIn.EndReading(iterEnd);
00715     while (iter != iterEnd)
00716     {
00717         if (*iter >= 0x0080 && *iter <= 0x00FF)
00718             return PR_TRUE;
00719         ++iter;
00720     }
00721     return PR_FALSE;
00722 }
00723 
00724 const char * nsDefaultURIFixup::GetFileSystemCharset()
00725 {
00726   if (mFsCharset.IsEmpty())
00727   {
00728     nsresult rv;
00729     nsCAutoString charset;
00730     nsCOMPtr<nsIPlatformCharset> plat(do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &rv));
00731     if (NS_SUCCEEDED(rv))
00732       rv = plat->GetCharset(kPlatformCharsetSel_FileName, charset);
00733 
00734     if (charset.IsEmpty())
00735       mFsCharset.AssignLiteral("ISO-8859-1");
00736     else
00737       mFsCharset.Assign(charset);
00738   }
00739 
00740   return mFsCharset.get();
00741 }
00742 
00743 const char * nsDefaultURIFixup::GetCharsetForUrlBar()
00744 {
00745   const char *charset = GetFileSystemCharset();
00746 #ifdef XP_MAC
00747   // check for "x-mac-" prefix
00748   if ((strlen(charset) >= 6) && charset[0] == 'x' && charset[2] == 'm')
00749   {
00750     if (!strcmp("x-mac-roman", charset))
00751       return "ISO-8859-1";
00752     // we can do more x-mac-xxxx mapping here
00753     // or somewhere in intl code like nsIPlatformCharset.
00754   }
00755 #endif
00756   return charset;
00757 }
00758 
00759 nsresult nsDefaultURIFixup::KeywordURIFixup(const nsACString & aURIString, 
00760                                             nsIURI** aURI)
00761 {
00762     // These are keyword formatted strings
00763     // "what is mozilla"
00764     // "what is mozilla?"
00765     // "docshell site:mozilla.org" - has no dot/colon in the first space-separated substring
00766     // "?mozilla" - anything that begins with a question mark
00767     // "?site:mozilla.org docshell"
00768 
00769     // These are not keyword formatted strings
00770     // "www.blah.com" - first space-separated substring contains a dot, doesn't start with "?"
00771     // "www.blah.com stuff"
00772     // "nonQualifiedHost:80" - first space-separated substring contains a colon, doesn't start with "?"
00773     // "nonQualifiedHost:80 args"
00774     // "nonQualifiedHost?"
00775     // "nonQualifiedHost?args"
00776     // "nonQualifiedHost?some args"
00777 
00778     PRInt32 dotLoc   = aURIString.FindChar('.');
00779     PRInt32 colonLoc = aURIString.FindChar(':');
00780     PRInt32 spaceLoc = aURIString.FindChar(' ');
00781     PRInt32 qMarkLoc = aURIString.FindChar('?');
00782 
00783     if ((dotLoc == kNotFound || (spaceLoc > 0 && spaceLoc < dotLoc)) &&
00784         (colonLoc == kNotFound || (spaceLoc > 0 && spaceLoc < colonLoc)) &&
00785         (spaceLoc > 0 && (qMarkLoc == kNotFound || spaceLoc < qMarkLoc)) ||
00786         qMarkLoc == 0)
00787     {
00788         KeywordToURI(aURIString, aURI);
00789     }
00790 
00791     if(*aURI)
00792         return NS_OK;
00793 
00794     return NS_ERROR_FAILURE;
00795 }
00796 
00797 
00798 nsresult NS_NewURIFixup(nsIURIFixup **aURIFixup)
00799 {
00800     nsDefaultURIFixup *fixup = new nsDefaultURIFixup;
00801     if (fixup == nsnull)
00802     {
00803         return NS_ERROR_OUT_OF_MEMORY;
00804     }
00805     return fixup->QueryInterface(NS_GET_IID(nsIURIFixup), (void **) aURIFixup);
00806 }
00807