IC for JSOP_CALLELEM (bug 604031, r=dmandelin).
[mozilla-central.git] / docshell / base / nsDefaultURIFixup.cpp
blob5e56cd40ad90c386a4b02017622c6b51e2a94320
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is the Mozilla browser.
18 * The Initial Developer of the Original Code is
19 * Netscape Communications, Inc.
20 * Portions created by the Initial Developer are Copyright (C) 1999
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
24 * Adam Lock <adamlock@netscape.com>
25 * Jeff Walden <jwalden+code@mit.edu>
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
41 #include "nsString.h"
42 #include "nsReadableUtils.h"
43 #include "nsNetUtil.h"
44 #include "nsEscape.h"
45 #include "nsCRT.h"
47 #include "nsIPrefService.h"
48 #include "nsIPrefLocalizedString.h"
49 #include "nsIPlatformCharset.h"
50 #include "nsILocalFile.h"
52 #ifdef MOZ_TOOLKIT_SEARCH
53 #include "nsIBrowserSearchService.h"
54 #endif
56 #include "nsIURIFixup.h"
57 #include "nsDefaultURIFixup.h"
59 /* Implementation file */
60 NS_IMPL_ISUPPORTS1(nsDefaultURIFixup, nsIURIFixup)
62 nsDefaultURIFixup::nsDefaultURIFixup()
64 /* member initializers and constructor code */
66 // Try and get the pref service
67 mPrefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID);
71 nsDefaultURIFixup::~nsDefaultURIFixup()
73 /* destructor code */
76 /* nsIURI createExposableURI (in nsIRUI aURI); */
77 NS_IMETHODIMP
78 nsDefaultURIFixup::CreateExposableURI(nsIURI *aURI, nsIURI **aReturn)
80 NS_ENSURE_ARG_POINTER(aURI);
81 NS_ENSURE_ARG_POINTER(aReturn);
83 PRBool isWyciwyg = PR_FALSE;
84 aURI->SchemeIs("wyciwyg", &isWyciwyg);
86 nsCAutoString userPass;
87 aURI->GetUserPass(userPass);
89 // most of the time we can just AddRef and return
90 if (!isWyciwyg && userPass.IsEmpty())
92 *aReturn = aURI;
93 NS_ADDREF(*aReturn);
94 return NS_OK;
97 // Rats, we have to massage the URI
98 nsCOMPtr<nsIURI> uri;
99 if (isWyciwyg)
101 nsCAutoString path;
102 nsresult rv = aURI->GetPath(path);
103 NS_ENSURE_SUCCESS(rv, rv);
105 PRUint32 pathLength = path.Length();
106 if (pathLength <= 2)
108 return NS_ERROR_FAILURE;
111 // Path is of the form "//123/http://foo/bar", with a variable number of digits.
112 // To figure out where the "real" URL starts, search path for a '/', starting at
113 // the third character.
114 PRInt32 slashIndex = path.FindChar('/', 2);
115 if (slashIndex == kNotFound)
117 return NS_ERROR_FAILURE;
120 // Get the charset of the original URI so we can pass it to our fixed up URI.
121 nsCAutoString charset;
122 aURI->GetOriginCharset(charset);
124 rv = NS_NewURI(getter_AddRefs(uri),
125 Substring(path, slashIndex + 1, pathLength - slashIndex - 1),
126 charset.get());
127 NS_ENSURE_SUCCESS(rv, rv);
129 else
131 // clone the URI so zapping user:pass doesn't change the original
132 nsresult rv = aURI->Clone(getter_AddRefs(uri));
133 NS_ENSURE_SUCCESS(rv, rv);
136 // hide user:pass unless overridden by pref
137 PRBool hideUserPass = PR_TRUE;
138 if (mPrefBranch)
140 mPrefBranch->GetBoolPref("browser.fixup.hide_user_pass", &hideUserPass);
142 if (hideUserPass)
143 uri->SetUserPass(EmptyCString());
145 // return the fixed-up URI
146 *aReturn = uri;
147 NS_ADDREF(*aReturn);
148 return NS_OK;
151 /* nsIURI createFixupURI (in nsAUTF8String aURIText, in unsigned long aFixupFlags); */
152 NS_IMETHODIMP
153 nsDefaultURIFixup::CreateFixupURI(const nsACString& aStringURI, PRUint32 aFixupFlags, nsIURI **aURI)
155 NS_ENSURE_ARG(!aStringURI.IsEmpty());
156 NS_ENSURE_ARG_POINTER(aURI);
158 nsresult rv;
159 *aURI = nsnull;
161 nsCAutoString uriString(aStringURI);
162 uriString.Trim(" "); // Cleanup the empty spaces that might be on each end.
164 // Eliminate embedded newlines, which single-line text fields now allow:
165 uriString.StripChars("\r\n");
167 NS_ENSURE_TRUE(!uriString.IsEmpty(), NS_ERROR_FAILURE);
169 nsCOMPtr<nsIIOService> ioService = do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
170 NS_ENSURE_SUCCESS(rv, rv);
171 nsCAutoString scheme;
172 ioService->ExtractScheme(aStringURI, scheme);
174 // View-source is a pseudo scheme. We're interested in fixing up the stuff
175 // after it. The easiest way to do that is to call this method again with the
176 // "view-source:" lopped off and then prepend it again afterwards.
178 if (scheme.LowerCaseEqualsLiteral("view-source"))
180 nsCOMPtr<nsIURI> uri;
181 PRUint32 newFixupFlags = aFixupFlags & ~FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
183 rv = CreateFixupURI(Substring(uriString,
184 sizeof("view-source:") - 1,
185 uriString.Length() -
186 (sizeof("view-source:") - 1)),
187 newFixupFlags, getter_AddRefs(uri));
188 if (NS_FAILED(rv))
189 return NS_ERROR_FAILURE;
190 nsCAutoString spec;
191 uri->GetSpec(spec);
192 uriString.Assign(NS_LITERAL_CSTRING("view-source:") + spec);
194 else {
195 // Check for if it is a file URL
196 FileURIFixup(uriString, aURI);
197 if(*aURI)
198 return NS_OK;
200 #if defined(XP_WIN) || defined(XP_OS2)
201 // Not a file URL, so translate '\' to '/' for convenience in the common protocols
202 // e.g. catch
204 // http:\\broken.com\address
205 // http:\\broken.com/blah
206 // broken.com\blah
208 // Code will also do partial fix up the following urls
210 // http:\\broken.com\address/somewhere\image.jpg (stops at first forward slash)
211 // http:\\broken.com\blah?arg=somearg\foo.jpg (stops at question mark)
212 // http:\\broken.com#odd\ref (stops at hash)
214 if (scheme.IsEmpty() ||
215 scheme.LowerCaseEqualsLiteral("http") ||
216 scheme.LowerCaseEqualsLiteral("https") ||
217 scheme.LowerCaseEqualsLiteral("ftp"))
219 // Walk the string replacing backslashes with forward slashes until
220 // the end is reached, or a question mark, or a hash, or a forward
221 // slash. The forward slash test is to stop before trampling over
222 // URIs which legitimately contain a mix of both forward and
223 // backward slashes.
224 nsCAutoString::iterator start;
225 nsCAutoString::iterator end;
226 uriString.BeginWriting(start);
227 uriString.EndWriting(end);
228 while (start != end) {
229 if (*start == '?' || *start == '#' || *start == '/')
230 break;
231 if (*start == '\\')
232 *start = '/';
233 ++start;
236 #endif
239 // For these protocols, use system charset instead of the default UTF-8,
240 // if the URI is non ASCII.
241 PRBool bAsciiURI = IsASCII(uriString);
242 PRBool bUseNonDefaultCharsetForURI =
243 !bAsciiURI &&
244 (scheme.IsEmpty() ||
245 scheme.LowerCaseEqualsLiteral("http") ||
246 scheme.LowerCaseEqualsLiteral("https") ||
247 scheme.LowerCaseEqualsLiteral("ftp") ||
248 scheme.LowerCaseEqualsLiteral("file"));
250 // Now we need to check whether "scheme" is something we don't
251 // really know about.
252 nsCOMPtr<nsIProtocolHandler> ourHandler, extHandler;
254 ioService->GetProtocolHandler(scheme.get(), getter_AddRefs(ourHandler));
255 extHandler = do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX"default");
257 if (ourHandler != extHandler || !PossiblyHostPortUrl(uriString)) {
258 // Just try to create an URL out of it
259 rv = NS_NewURI(aURI, uriString,
260 bUseNonDefaultCharsetForURI ? GetCharsetForUrlBar() : nsnull);
262 if (!*aURI && rv != NS_ERROR_MALFORMED_URI) {
263 return rv;
267 if (*aURI) {
268 if (aFixupFlags & FIXUP_FLAGS_MAKE_ALTERNATE_URI)
269 MakeAlternateURI(*aURI);
270 return NS_OK;
273 // See if it is a keyword
274 // Test whether keywords need to be fixed up
275 PRBool fixupKeywords = PR_FALSE;
276 if (aFixupFlags & FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP) {
277 if (mPrefBranch)
279 NS_ENSURE_SUCCESS(mPrefBranch->GetBoolPref("keyword.enabled", &fixupKeywords), NS_ERROR_FAILURE);
281 if (fixupKeywords)
283 KeywordURIFixup(uriString, aURI);
284 if(*aURI)
285 return NS_OK;
289 // Prune duff protocol schemes
291 // ://totallybroken.url.com
292 // //shorthand.url.com
294 if (StringBeginsWith(uriString, NS_LITERAL_CSTRING("://")))
296 uriString = StringTail(uriString, uriString.Length() - 3);
298 else if (StringBeginsWith(uriString, NS_LITERAL_CSTRING("//")))
300 uriString = StringTail(uriString, uriString.Length() - 2);
303 // Add ftp:// or http:// to front of url if it has no spec
305 // Should fix:
307 // no-scheme.com
308 // ftp.no-scheme.com
309 // ftp4.no-scheme.com
310 // no-scheme.com/query?foo=http://www.foo.com
312 PRInt32 schemeDelim = uriString.Find("://",0);
313 PRInt32 firstDelim = uriString.FindCharInSet("/:");
314 if (schemeDelim <= 0 ||
315 (firstDelim != -1 && schemeDelim > firstDelim)) {
316 // find host name
317 PRInt32 hostPos = uriString.FindCharInSet("/:?#");
318 if (hostPos == -1)
319 hostPos = uriString.Length();
321 // extract host name
322 nsCAutoString hostSpec;
323 uriString.Left(hostSpec, hostPos);
325 // insert url spec corresponding to host name
326 if (IsLikelyFTP(hostSpec))
327 uriString.Assign(NS_LITERAL_CSTRING("ftp://") + uriString);
328 else
329 uriString.Assign(NS_LITERAL_CSTRING("http://") + uriString);
331 // For ftp & http, we want to use system charset.
332 if (!bAsciiURI)
333 bUseNonDefaultCharsetForURI = PR_TRUE;
334 } // end if checkprotocol
336 rv = NS_NewURI(aURI, uriString, bUseNonDefaultCharsetForURI ? GetCharsetForUrlBar() : nsnull);
338 // Did the caller want us to try an alternative URI?
339 // If so, attempt to fixup http://foo into http://www.foo.com
341 if (*aURI && aFixupFlags & FIXUP_FLAGS_MAKE_ALTERNATE_URI) {
342 MakeAlternateURI(*aURI);
345 // If we still haven't been able to construct a valid URI, try to force a
346 // keyword match. This catches search strings with '.' or ':' in them.
347 if (!*aURI && fixupKeywords)
349 KeywordToURI(aStringURI, aURI);
350 if(*aURI)
351 return NS_OK;
354 return rv;
357 static nsresult MangleKeywordIntoURI(const char *aKeyword, const char *aURL,
358 nsCString& query)
360 query = (*aKeyword == '?') ? (aKeyword + 1) : aKeyword;
361 query.Trim(" "); // pull leading/trailing spaces.
363 // encode
364 char * encQuery = nsEscape(query.get(), url_XPAlphas);
365 if (!encQuery) return NS_ERROR_OUT_OF_MEMORY;
366 query.Adopt(encQuery);
368 // prepend the query with the keyword url
369 // XXX this url should come from somewhere else
370 query.Insert(aURL, 0);
371 return NS_OK;
374 NS_IMETHODIMP nsDefaultURIFixup::KeywordToURI(const nsACString& aKeyword,
375 nsIURI **aURI)
377 *aURI = nsnull;
378 NS_ENSURE_STATE(mPrefBranch);
380 nsXPIDLCString url;
381 nsCOMPtr<nsIPrefLocalizedString> keywordURL;
382 mPrefBranch->GetComplexValue("keyword.URL",
383 NS_GET_IID(nsIPrefLocalizedString),
384 getter_AddRefs(keywordURL));
386 if (keywordURL) {
387 nsXPIDLString wurl;
388 keywordURL->GetData(getter_Copies(wurl));
389 CopyUTF16toUTF8(wurl, url);
390 } else {
391 // Fall back to a non-localized pref, for backwards compat
392 mPrefBranch->GetCharPref("keyword.URL", getter_Copies(url));
395 // If the pref is set and non-empty, use it.
396 if (!url.IsEmpty()) {
397 nsCAutoString spec;
398 nsresult rv = MangleKeywordIntoURI(PromiseFlatCString(aKeyword).get(),
399 url.get(), spec);
400 if (NS_FAILED(rv)) return rv;
402 return NS_NewURI(aURI, spec);
405 #ifdef MOZ_TOOLKIT_SEARCH
406 // Try falling back to the search service's default search engine
407 nsCOMPtr<nsIBrowserSearchService> searchSvc = do_GetService("@mozilla.org/browser/search-service;1");
408 if (searchSvc) {
409 nsCOMPtr<nsISearchEngine> defaultEngine;
410 searchSvc->GetOriginalDefaultEngine(getter_AddRefs(defaultEngine));
411 if (defaultEngine) {
412 nsCOMPtr<nsISearchSubmission> submission;
413 // We want to allow default search plugins to specify alternate
414 // parameters that are specific to keyword searches. For the moment,
415 // do this by first looking for a magic
416 // "application/x-moz-keywordsearch" submission type. In the future,
417 // we should instead use a solution that relies on bug 587780.
418 defaultEngine->GetSubmission(NS_ConvertUTF8toUTF16(aKeyword),
419 NS_LITERAL_STRING("application/x-moz-keywordsearch"),
420 getter_AddRefs(submission));
421 // If getting the special x-moz-keywordsearch submission type failed,
422 // fall back to the default response type.
423 if (!submission) {
424 defaultEngine->GetSubmission(NS_ConvertUTF8toUTF16(aKeyword),
425 EmptyString(),
426 getter_AddRefs(submission));
429 if (submission) {
430 // The submission depends on POST data (i.e. the search engine's
431 // "method" is POST), we can't use this engine for keyword
432 // searches
433 nsCOMPtr<nsIInputStream> postData;
434 submission->GetPostData(getter_AddRefs(postData));
435 if (postData) {
436 return NS_ERROR_NOT_AVAILABLE;
439 return submission->GetUri(aURI);
443 #endif
445 // out of options
446 return NS_ERROR_NOT_AVAILABLE;
449 PRBool nsDefaultURIFixup::MakeAlternateURI(nsIURI *aURI)
451 if (!mPrefBranch)
453 return PR_FALSE;
455 PRBool makeAlternate = PR_TRUE;
456 mPrefBranch->GetBoolPref("browser.fixup.alternate.enabled", &makeAlternate);
457 if (!makeAlternate)
459 return PR_FALSE;
462 // Code only works for http. Not for any other protocol including https!
463 PRBool isHttp = PR_FALSE;
464 aURI->SchemeIs("http", &isHttp);
465 if (!isHttp) {
466 return PR_FALSE;
469 // Security - URLs with user / password info should NOT be fixed up
470 nsCAutoString userpass;
471 aURI->GetUserPass(userpass);
472 if (!userpass.IsEmpty()) {
473 return PR_FALSE;
476 nsCAutoString oldHost;
477 nsCAutoString newHost;
478 aURI->GetHost(oldHost);
480 // Count the dots
481 PRInt32 numDots = 0;
482 nsReadingIterator<char> iter;
483 nsReadingIterator<char> iterEnd;
484 oldHost.BeginReading(iter);
485 oldHost.EndReading(iterEnd);
486 while (iter != iterEnd) {
487 if (*iter == '.')
488 numDots++;
489 ++iter;
493 nsresult rv;
495 // Get the prefix and suffix to stick onto the new hostname. By default these
496 // are www. & .com but they could be any other value, e.g. www. & .org
498 nsCAutoString prefix("www.");
499 nsXPIDLCString prefPrefix;
500 rv = mPrefBranch->GetCharPref("browser.fixup.alternate.prefix", getter_Copies(prefPrefix));
501 if (NS_SUCCEEDED(rv))
503 prefix.Assign(prefPrefix);
506 nsCAutoString suffix(".com");
507 nsXPIDLCString prefSuffix;
508 rv = mPrefBranch->GetCharPref("browser.fixup.alternate.suffix", getter_Copies(prefSuffix));
509 if (NS_SUCCEEDED(rv))
511 suffix.Assign(prefSuffix);
514 if (numDots == 0)
516 newHost.Assign(prefix);
517 newHost.Append(oldHost);
518 newHost.Append(suffix);
520 else if (numDots == 1)
522 if (!prefix.IsEmpty() &&
523 oldHost.EqualsIgnoreCase(prefix.get(), prefix.Length())) {
524 newHost.Assign(oldHost);
525 newHost.Append(suffix);
527 else if (!suffix.IsEmpty()) {
528 newHost.Assign(prefix);
529 newHost.Append(oldHost);
531 else
533 // Do nothing
534 return PR_FALSE;
537 else
539 // Do nothing
540 return PR_FALSE;
543 if (newHost.IsEmpty()) {
544 return PR_FALSE;
547 // Assign the new host string over the old one
548 aURI->SetHost(newHost);
549 return PR_TRUE;
553 * Check if the host name starts with ftp\d*\. and it's not directly followed
554 * by the tld.
556 PRBool nsDefaultURIFixup::IsLikelyFTP(const nsCString &aHostSpec)
558 PRBool likelyFTP = PR_FALSE;
559 if (aHostSpec.EqualsIgnoreCase("ftp", 3)) {
560 nsACString::const_iterator iter;
561 nsACString::const_iterator end;
562 aHostSpec.BeginReading(iter);
563 aHostSpec.EndReading(end);
564 iter.advance(3); // move past the "ftp" part
566 while (iter != end)
568 if (*iter == '.') {
569 // now make sure the name has at least one more dot in it
570 ++iter;
571 while (iter != end)
573 if (*iter == '.') {
574 likelyFTP = PR_TRUE;
575 break;
577 ++iter;
579 break;
581 else if (!nsCRT::IsAsciiDigit(*iter)) {
582 break;
584 ++iter;
587 return likelyFTP;
590 nsresult nsDefaultURIFixup::FileURIFixup(const nsACString& aStringURI,
591 nsIURI** aURI)
593 nsCAutoString uriSpecOut;
595 nsresult rv = ConvertFileToStringURI(aStringURI, uriSpecOut);
596 if (NS_SUCCEEDED(rv))
598 // if this is file url, uriSpecOut is already in FS charset
599 if(NS_SUCCEEDED(NS_NewURI(aURI, uriSpecOut.get(), nsnull)))
600 return NS_OK;
602 return NS_ERROR_FAILURE;
605 nsresult nsDefaultURIFixup::ConvertFileToStringURI(const nsACString& aIn,
606 nsCString& aOut)
608 PRBool attemptFixup = PR_FALSE;
610 #if defined(XP_WIN) || defined(XP_OS2)
611 // Check for \ in the url-string or just a drive (PC)
612 if(kNotFound != aIn.FindChar('\\') ||
613 (aIn.Length() == 2 && (aIn.Last() == ':' || aIn.Last() == '|')))
615 attemptFixup = PR_TRUE;
617 #elif defined(XP_UNIX) || defined(XP_BEOS)
618 // Check if it starts with / (UNIX)
619 if(aIn.First() == '/')
621 attemptFixup = PR_TRUE;
623 #else
624 // Do nothing (All others for now)
625 #endif
627 if (attemptFixup)
629 // Test if this is a valid path by trying to create a local file
630 // object. The URL of that is returned if successful.
632 // NOTE: Please be sure to check that the call to NS_NewLocalFile
633 // rejects bad file paths when using this code on a new
634 // platform.
636 nsCOMPtr<nsILocalFile> filePath;
637 nsresult rv;
639 // this is not the real fix but a temporary fix
640 // in order to really fix the problem, we need to change the
641 // nsICmdLineService interface to use wstring to pass paramenters
642 // instead of string since path name and other argument could be
643 // in non ascii.(see bug 87127) Since it is too risky to make interface change right
644 // now, we decide not to do so now.
645 // Therefore, the aIn we receive here maybe already in damage form
646 // (e.g. treat every bytes as ISO-8859-1 and cast up to PRUnichar
647 // while the real data could be in file system charset )
648 // we choice the following logic which will work for most of the case.
649 // Case will still failed only if it meet ALL the following condiction:
650 // 1. running on CJK, Russian, or Greek system, and
651 // 2. user type it from URL bar
652 // 3. the file name contains character in the range of
653 // U+00A1-U+00FF but encode as different code point in file
654 // system charset (e.g. ACP on window)- this is very rare case
655 // We should remove this logic and convert to File system charset here
656 // once we change nsICmdLineService to use wstring and ensure
657 // all the Unicode data come in is correctly converted.
658 // XXXbz nsICmdLineService doesn't hand back unicode, so in some cases
659 // what we have is actually a "utf8" version of a "utf16" string that's
660 // actually byte-expanded native-encoding data. Someone upstream needs
661 // to stop using AssignWithConversion and do things correctly. See bug
662 // 58866 for what happens if we remove this
663 // PossiblyByteExpandedFileName check.
664 NS_ConvertUTF8toUTF16 in(aIn);
665 if (PossiblyByteExpandedFileName(in)) {
666 // removes high byte
667 rv = NS_NewNativeLocalFile(NS_LossyConvertUTF16toASCII(in), PR_FALSE, getter_AddRefs(filePath));
669 else {
670 // input is unicode
671 rv = NS_NewLocalFile(in, PR_FALSE, getter_AddRefs(filePath));
674 if (NS_SUCCEEDED(rv))
676 NS_GetURLSpecFromFile(filePath, aOut);
677 return NS_OK;
681 return NS_ERROR_FAILURE;
684 PRBool nsDefaultURIFixup::PossiblyHostPortUrl(const nsACString &aUrl)
686 // Oh dear, the protocol is invalid. Test if the protocol might
687 // actually be a url without a protocol:
689 // http://www.faqs.org/rfcs/rfc1738.html
690 // http://www.faqs.org/rfcs/rfc2396.html
692 // e.g. Anything of the form:
694 // <hostname>:<port> or
695 // <hostname>:<port>/
697 // Where <hostname> is a string of alphanumeric characters and dashes
698 // separated by dots.
699 // and <port> is a 5 or less digits. This actually breaks the rfc2396
700 // definition of a scheme which allows dots in schemes.
702 // Note:
703 // People expecting this to work with
704 // <user>:<password>@<host>:<port>/<url-path> will be disappointed!
706 // Note: Parser could be a lot tighter, tossing out silly hostnames
707 // such as those containing consecutive dots and so on.
709 // Read the hostname which should of the form
710 // [a-zA-Z0-9\-]+(\.[a-zA-Z0-9\-]+)*:
712 nsACString::const_iterator iterBegin;
713 nsACString::const_iterator iterEnd;
714 aUrl.BeginReading(iterBegin);
715 aUrl.EndReading(iterEnd);
716 nsACString::const_iterator iter = iterBegin;
718 while (iter != iterEnd)
720 PRUint32 chunkSize = 0;
721 // Parse a chunk of the address
722 while (iter != iterEnd &&
723 (*iter == '-' ||
724 nsCRT::IsAsciiAlpha(*iter) ||
725 nsCRT::IsAsciiDigit(*iter)))
727 ++chunkSize;
728 ++iter;
730 if (chunkSize == 0 || iter == iterEnd)
732 return PR_FALSE;
734 if (*iter == ':')
736 // Go onto checking the for the digits
737 break;
739 if (*iter != '.')
741 // Whatever it is, it ain't a hostname!
742 return PR_FALSE;
744 ++iter;
746 if (iter == iterEnd)
748 // No point continuing since there is no colon
749 return PR_FALSE;
751 ++iter;
753 // Count the number of digits after the colon and before the
754 // next forward slash (or end of string)
756 PRUint32 digitCount = 0;
757 while (iter != iterEnd && digitCount <= 5)
759 if (nsCRT::IsAsciiDigit(*iter))
761 digitCount++;
763 else if (*iter == '/')
765 break;
767 else
769 // Whatever it is, it ain't a port!
770 return PR_FALSE;
772 ++iter;
774 if (digitCount == 0 || digitCount > 5)
776 // No digits or more digits than a port would have.
777 return PR_FALSE;
780 // Yes, it's possibly a host:port url
781 return PR_TRUE;
784 PRBool nsDefaultURIFixup::PossiblyByteExpandedFileName(const nsAString& aIn)
786 // XXXXX HACK XXXXX : please don't copy this code.
787 // There are cases where aIn contains the locale byte chars padded to short
788 // (thus the name "ByteExpanded"); whereas other cases
789 // have proper Unicode code points.
790 // This is a temporary fix. Please refer to 58866, 86948
792 nsReadingIterator<PRUnichar> iter;
793 nsReadingIterator<PRUnichar> iterEnd;
794 aIn.BeginReading(iter);
795 aIn.EndReading(iterEnd);
796 while (iter != iterEnd)
798 if (*iter >= 0x0080 && *iter <= 0x00FF)
799 return PR_TRUE;
800 ++iter;
802 return PR_FALSE;
805 const char * nsDefaultURIFixup::GetFileSystemCharset()
807 if (mFsCharset.IsEmpty())
809 nsresult rv;
810 nsCAutoString charset;
811 nsCOMPtr<nsIPlatformCharset> plat(do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &rv));
812 if (NS_SUCCEEDED(rv))
813 rv = plat->GetCharset(kPlatformCharsetSel_FileName, charset);
815 if (charset.IsEmpty())
816 mFsCharset.AssignLiteral("ISO-8859-1");
817 else
818 mFsCharset.Assign(charset);
821 return mFsCharset.get();
824 const char * nsDefaultURIFixup::GetCharsetForUrlBar()
826 const char *charset = GetFileSystemCharset();
827 #ifdef XP_MAC
828 // check for "x-mac-" prefix
829 if ((strlen(charset) >= 6) && charset[0] == 'x' && charset[2] == 'm')
831 if (!strcmp("x-mac-roman", charset))
832 return "ISO-8859-1";
833 // we can do more x-mac-xxxx mapping here
834 // or somewhere in intl code like nsIPlatformCharset.
836 #endif
837 return charset;
840 nsresult nsDefaultURIFixup::KeywordURIFixup(const nsACString & aURIString,
841 nsIURI** aURI)
843 // These are keyword formatted strings
844 // "what is mozilla"
845 // "what is mozilla?"
846 // "docshell site:mozilla.org" - has no dot/colon in the first space-separated substring
847 // "?mozilla" - anything that begins with a question mark
848 // "?site:mozilla.org docshell"
849 // Things that have a quote before the first dot/colon
851 // These are not keyword formatted strings
852 // "www.blah.com" - first space-separated substring contains a dot, doesn't start with "?"
853 // "www.blah.com stuff"
854 // "nonQualifiedHost:80" - first space-separated substring contains a colon, doesn't start with "?"
855 // "nonQualifiedHost:80 args"
856 // "nonQualifiedHost?"
857 // "nonQualifiedHost?args"
858 // "nonQualifiedHost?some args"
860 // Note: PRUint32(kNotFound) is greater than any actual location
861 // in practice. So if we cast all locations to PRUint32, then a <
862 // b guarantees that either b is kNotFound and a is found, or both
863 // are found and a found before b.
864 PRUint32 dotLoc = PRUint32(aURIString.FindChar('.'));
865 PRUint32 colonLoc = PRUint32(aURIString.FindChar(':'));
866 PRUint32 spaceLoc = PRUint32(aURIString.FindChar(' '));
867 if (spaceLoc == 0) {
868 // Treat this as not found
869 spaceLoc = PRUint32(kNotFound);
871 PRUint32 qMarkLoc = PRUint32(aURIString.FindChar('?'));
872 PRUint32 quoteLoc = NS_MIN(PRUint32(aURIString.FindChar('"')),
873 PRUint32(aURIString.FindChar('\'')));
875 if (((spaceLoc < dotLoc || quoteLoc < dotLoc) &&
876 (spaceLoc < colonLoc || quoteLoc < colonLoc) &&
877 (spaceLoc < qMarkLoc || quoteLoc < qMarkLoc)) ||
878 qMarkLoc == 0)
880 KeywordToURI(aURIString, aURI);
883 if(*aURI)
884 return NS_OK;
886 return NS_ERROR_FAILURE;
890 nsresult NS_NewURIFixup(nsIURIFixup **aURIFixup)
892 nsDefaultURIFixup *fixup = new nsDefaultURIFixup;
893 if (fixup == nsnull)
895 return NS_ERROR_OUT_OF_MEMORY;
897 return fixup->QueryInterface(NS_GET_IID(nsIURIFixup), (void **) aURIFixup);