1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
13 #ifdef MOZ_TOOLKIT_SEARCH
14 #include "nsIBrowserSearchService.h"
17 #include "nsIURIFixup.h"
18 #include "nsDefaultURIFixup.h"
19 #include "mozilla/Preferences.h"
20 #include "mozilla/dom/ContentChild.h"
21 #include "mozilla/ipc/InputStreamUtils.h"
22 #include "mozilla/ipc/URIUtils.h"
23 #include "nsIObserverService.h"
24 #include "nsXULAppAPI.h"
26 // Used to check if external protocol schemes are usable
27 #include "nsCExternalHandlerService.h"
28 #include "nsIExternalProtocolService.h"
30 using namespace mozilla
;
32 /* Implementation file */
33 NS_IMPL_ISUPPORTS(nsDefaultURIFixup
, nsIURIFixup
)
35 static bool sInitializedPrefCaches
= false;
36 static bool sFixTypos
= true;
37 static bool sFixupKeywords
= true;
39 nsDefaultURIFixup::nsDefaultURIFixup()
41 /* member initializers and constructor code */
45 nsDefaultURIFixup::~nsDefaultURIFixup()
50 /* nsIURI createExposableURI (in nsIURI aURI); */
52 nsDefaultURIFixup::CreateExposableURI(nsIURI
*aURI
, nsIURI
**aReturn
)
54 NS_ENSURE_ARG_POINTER(aURI
);
55 NS_ENSURE_ARG_POINTER(aReturn
);
57 bool isWyciwyg
= false;
58 aURI
->SchemeIs("wyciwyg", &isWyciwyg
);
60 nsAutoCString userPass
;
61 aURI
->GetUserPass(userPass
);
63 // most of the time we can just AddRef and return
64 if (!isWyciwyg
&& userPass
.IsEmpty())
71 // Rats, we have to massage the URI
76 nsresult rv
= aURI
->GetPath(path
);
77 NS_ENSURE_SUCCESS(rv
, rv
);
79 uint32_t pathLength
= path
.Length();
82 return NS_ERROR_FAILURE
;
85 // Path is of the form "//123/http://foo/bar", with a variable number of digits.
86 // To figure out where the "real" URL starts, search path for a '/', starting at
87 // the third character.
88 int32_t slashIndex
= path
.FindChar('/', 2);
89 if (slashIndex
== kNotFound
)
91 return NS_ERROR_FAILURE
;
94 // Get the charset of the original URI so we can pass it to our fixed up URI.
95 nsAutoCString charset
;
96 aURI
->GetOriginCharset(charset
);
98 rv
= NS_NewURI(getter_AddRefs(uri
),
99 Substring(path
, slashIndex
+ 1, pathLength
- slashIndex
- 1),
101 NS_ENSURE_SUCCESS(rv
, rv
);
105 // clone the URI so zapping user:pass doesn't change the original
106 nsresult rv
= aURI
->Clone(getter_AddRefs(uri
));
107 NS_ENSURE_SUCCESS(rv
, rv
);
110 // hide user:pass unless overridden by pref
111 if (Preferences::GetBool("browser.fixup.hide_user_pass", true))
113 uri
->SetUserPass(EmptyCString());
116 // return the fixed-up URI
122 /* nsIURI createFixupURI (in nsAUTF8String aURIText, in unsigned long aFixupFlags); */
124 nsDefaultURIFixup::CreateFixupURI(const nsACString
& aStringURI
, uint32_t aFixupFlags
,
125 nsIInputStream
**aPostData
, nsIURI
**aURI
)
127 nsCOMPtr
<nsIURIFixupInfo
> fixupInfo
;
128 nsresult rv
= GetFixupURIInfo(aStringURI
, aFixupFlags
, aPostData
,
129 getter_AddRefs(fixupInfo
));
130 NS_ENSURE_SUCCESS(rv
, rv
);
132 fixupInfo
->GetPreferredURI(aURI
);
137 nsDefaultURIFixup::GetFixupURIInfo(const nsACString
& aStringURI
, uint32_t aFixupFlags
,
138 nsIInputStream
**aPostData
, nsIURIFixupInfo
**aInfo
)
140 NS_ENSURE_ARG(!aStringURI
.IsEmpty());
144 nsAutoCString
uriString(aStringURI
);
146 // Eliminate embedded newlines, which single-line text fields now allow:
147 uriString
.StripChars("\r\n");
148 // Cleanup the empty spaces that might be on each end:
151 NS_ENSURE_TRUE(!uriString
.IsEmpty(), NS_ERROR_FAILURE
);
153 nsRefPtr
<nsDefaultURIFixupInfo
> info
= new nsDefaultURIFixupInfo(uriString
);
154 NS_ADDREF(*aInfo
= info
);
156 nsCOMPtr
<nsIIOService
> ioService
= do_GetService(NS_IOSERVICE_CONTRACTID
, &rv
);
157 NS_ENSURE_SUCCESS(rv
, rv
);
158 nsAutoCString scheme
;
159 ioService
->ExtractScheme(aStringURI
, scheme
);
161 // View-source is a pseudo scheme. We're interested in fixing up the stuff
162 // after it. The easiest way to do that is to call this method again with the
163 // "view-source:" lopped off and then prepend it again afterwards.
165 if (scheme
.LowerCaseEqualsLiteral("view-source"))
167 nsCOMPtr
<nsIURIFixupInfo
> uriInfo
;
168 uint32_t newFixupFlags
= aFixupFlags
& ~FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP
;
170 rv
= GetFixupURIInfo(Substring(uriString
,
171 sizeof("view-source:") - 1,
173 (sizeof("view-source:") - 1)),
174 newFixupFlags
, aPostData
, getter_AddRefs(uriInfo
));
176 return NS_ERROR_FAILURE
;
178 nsCOMPtr
<nsIURI
> uri
;
179 uriInfo
->GetPreferredURI(getter_AddRefs(uri
));
181 return NS_ERROR_FAILURE
;
183 uriString
.AssignLiteral("view-source:");
184 uriString
.Append(spec
);
187 // Check for if it is a file URL
188 nsCOMPtr
<nsIURI
> uri
;
189 FileURIFixup(uriString
, getter_AddRefs(uri
));
190 // NB: FileURIFixup only returns a URI if it had to fix the protocol to
191 // do so, so passing in file:///foo/bar will not hit this path:
194 uri
.swap(info
->mFixedURI
);
195 info
->mPreferredURI
= info
->mFixedURI
;
196 info
->mFixupChangedProtocol
= true;
201 // Not a file URL, so translate '\' to '/' for convenience in the common protocols
204 // http:\\broken.com\address
205 // http:\\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
224 nsAutoCString::iterator start
;
225 nsAutoCString::iterator end
;
226 uriString
.BeginWriting(start
);
227 uriString
.EndWriting(end
);
228 while (start
!= end
) {
229 if (*start
== '?' || *start
== '#' || *start
== '/')
239 if (!sInitializedPrefCaches
) {
240 // Check if we want to fix up common scheme typos.
241 rv
= Preferences::AddBoolVarCache(&sFixTypos
,
242 "browser.fixup.typo.scheme",
244 MOZ_ASSERT(NS_SUCCEEDED(rv
),
245 "Failed to observe \"browser.fixup.typo.scheme\"");
247 rv
= Preferences::AddBoolVarCache(&sFixupKeywords
, "keyword.enabled",
249 MOZ_ASSERT(NS_SUCCEEDED(rv
), "Failed to observe \"keyword.enabled\"");
250 sInitializedPrefCaches
= true;
253 // Fix up common scheme typos.
254 if (sFixTypos
&& (aFixupFlags
& FIXUP_FLAG_FIX_SCHEME_TYPOS
)) {
256 // Fast-path for common cases.
257 if (scheme
.IsEmpty() ||
258 scheme
.LowerCaseEqualsLiteral("http") ||
259 scheme
.LowerCaseEqualsLiteral("https") ||
260 scheme
.LowerCaseEqualsLiteral("ftp") ||
261 scheme
.LowerCaseEqualsLiteral("file")) {
263 } else if (scheme
.LowerCaseEqualsLiteral("ttp")) {
265 uriString
.Replace(0, 3, "http");
266 scheme
.AssignLiteral("http");
267 info
->mFixupChangedProtocol
= true;
268 } else if (scheme
.LowerCaseEqualsLiteral("ttps")) {
270 uriString
.Replace(0, 4, "https");
271 scheme
.AssignLiteral("https");
272 info
->mFixupChangedProtocol
= true;
273 } else if (scheme
.LowerCaseEqualsLiteral("tps")) {
275 uriString
.Replace(0, 3, "https");
276 scheme
.AssignLiteral("https");
277 info
->mFixupChangedProtocol
= true;
278 } else if (scheme
.LowerCaseEqualsLiteral("ps")) {
280 uriString
.Replace(0, 2, "https");
281 scheme
.AssignLiteral("https");
282 info
->mFixupChangedProtocol
= true;
283 } else if (scheme
.LowerCaseEqualsLiteral("ile")) {
285 uriString
.Replace(0, 3, "file");
286 scheme
.AssignLiteral("file");
287 info
->mFixupChangedProtocol
= true;
288 } else if (scheme
.LowerCaseEqualsLiteral("le")) {
290 uriString
.Replace(0, 2, "file");
291 scheme
.AssignLiteral("file");
292 info
->mFixupChangedProtocol
= true;
296 // Now we need to check whether "scheme" is something we don't
297 // really know about.
298 nsCOMPtr
<nsIProtocolHandler
> ourHandler
, extHandler
;
300 ioService
->GetProtocolHandler(scheme
.get(), getter_AddRefs(ourHandler
));
301 extHandler
= do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX
"default");
303 nsCOMPtr
<nsIURI
> uri
;
304 if (ourHandler
!= extHandler
|| !PossiblyHostPortUrl(uriString
)) {
305 // Just try to create an URL out of it
306 rv
= NS_NewURI(getter_AddRefs(uri
), uriString
, nullptr);
307 if (NS_SUCCEEDED(rv
)) {
308 info
->mFixedURI
= uri
;
311 if (!uri
&& rv
!= NS_ERROR_MALFORMED_URI
) {
316 if (uri
&& ourHandler
== extHandler
&& sFixupKeywords
&&
317 (aFixupFlags
& FIXUP_FLAG_FIX_SCHEME_TYPOS
)) {
318 nsCOMPtr
<nsIExternalProtocolService
> extProtService
=
319 do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID
);
320 if (extProtService
) {
321 bool handlerExists
= false;
322 rv
= extProtService
->ExternalProtocolHandlerExists(scheme
.get(), &handlerExists
);
326 // This basically means we're dealing with a theoretically valid
327 // URI... but we have no idea how to load it. (e.g. "christmas:humbug")
328 // It's more likely the user wants to search, and so we
329 // chuck this over to their preferred search provider instead:
330 if (!handlerExists
) {
331 nsresult rv
= KeywordToURI(uriString
, aPostData
, getter_AddRefs(uri
));
332 if (NS_SUCCEEDED(rv
) && uri
) {
333 info
->mFixupUsedKeyword
= true;
340 if (aFixupFlags
& FIXUP_FLAGS_MAKE_ALTERNATE_URI
)
341 info
->mFixupCreatedAlternateURI
= MakeAlternateURI(uri
);
342 info
->mPreferredURI
= uri
;
346 // Fix up protocol string before calling KeywordURIFixup, because
347 // it cares about the hostname of such URIs:
348 nsCOMPtr
<nsIURI
> uriWithProtocol
;
349 bool inputHadDuffProtocol
= false;
351 // Prune duff protocol schemes
353 // ://totallybroken.url.com
354 // //shorthand.url.com
356 if (StringBeginsWith(uriString
, NS_LITERAL_CSTRING("://")))
358 uriString
= StringTail(uriString
, uriString
.Length() - 3);
359 inputHadDuffProtocol
= true;
360 } else if (StringBeginsWith(uriString
, NS_LITERAL_CSTRING("//"))) {
361 uriString
= StringTail(uriString
, uriString
.Length() - 2);
362 inputHadDuffProtocol
= true;
365 // NB: this rv gets returned at the end of this method if we never
366 // do a keyword fixup after this (because the pref or the flags passed
367 // might not let us).
368 rv
= FixupURIProtocol(uriString
, info
, getter_AddRefs(uriWithProtocol
));
369 if (uriWithProtocol
) {
370 info
->mFixedURI
= uriWithProtocol
;
373 // See if it is a keyword
374 // Test whether keywords need to be fixed up
375 if (sFixupKeywords
&& (aFixupFlags
& FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP
) &&
376 !inputHadDuffProtocol
) {
377 KeywordURIFixup(uriString
, info
, aPostData
);
378 if (info
->mPreferredURI
)
382 // Did the caller want us to try an alternative URI?
383 // If so, attempt to fixup http://foo into http://www.foo.com
385 if (info
->mFixedURI
&& aFixupFlags
& FIXUP_FLAGS_MAKE_ALTERNATE_URI
) {
386 info
->mFixupCreatedAlternateURI
= MakeAlternateURI(info
->mFixedURI
);
389 // If we still haven't been able to construct a valid URI, try to force a
390 // keyword match. This catches search strings with '.' or ':' in them.
393 info
->mPreferredURI
= info
->mFixedURI
;
395 else if (sFixupKeywords
&& (aFixupFlags
& FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP
))
397 rv
= KeywordToURI(aStringURI
, aPostData
, getter_AddRefs(info
->mPreferredURI
));
398 if (NS_SUCCEEDED(rv
) && info
->mPreferredURI
)
400 info
->mFixupUsedKeyword
= true;
408 NS_IMETHODIMP
nsDefaultURIFixup::KeywordToURI(const nsACString
& aKeyword
,
409 nsIInputStream
**aPostData
,
414 *aPostData
= nullptr;
416 NS_ENSURE_STATE(Preferences::GetRootBranch());
418 // Strip leading "?" and leading/trailing spaces from aKeyword
419 nsAutoCString
keyword(aKeyword
);
420 if (StringBeginsWith(keyword
, NS_LITERAL_CSTRING("?"))) {
425 if (XRE_GetProcessType() == GeckoProcessType_Content
) {
426 dom::ContentChild
* contentChild
= dom::ContentChild::GetSingleton();
428 return NS_ERROR_NOT_AVAILABLE
;
431 ipc::OptionalInputStreamParams postData
;
432 ipc::OptionalURIParams uri
;
433 if (!contentChild
->SendKeywordToURI(keyword
, &postData
, &uri
)) {
434 return NS_ERROR_FAILURE
;
438 nsTArray
<ipc::FileDescriptor
> fds
;
439 nsCOMPtr
<nsIInputStream
> temp
= DeserializeInputStream(postData
, fds
);
440 temp
.forget(aPostData
);
442 MOZ_ASSERT(fds
.IsEmpty());
445 nsCOMPtr
<nsIURI
> temp
= DeserializeURI(uri
);
450 #ifdef MOZ_TOOLKIT_SEARCH
451 // Try falling back to the search service's default search engine
452 nsCOMPtr
<nsIBrowserSearchService
> searchSvc
= do_GetService("@mozilla.org/browser/search-service;1");
454 nsCOMPtr
<nsISearchEngine
> defaultEngine
;
455 searchSvc
->GetDefaultEngine(getter_AddRefs(defaultEngine
));
457 nsCOMPtr
<nsISearchSubmission
> submission
;
458 nsAutoString responseType
;
459 // We allow default search plugins to specify alternate
460 // parameters that are specific to keyword searches.
461 NS_NAMED_LITERAL_STRING(mozKeywordSearch
, "application/x-moz-keywordsearch");
462 bool supportsResponseType
= false;
463 defaultEngine
->SupportsResponseType(mozKeywordSearch
, &supportsResponseType
);
464 if (supportsResponseType
) {
465 responseType
.Assign(mozKeywordSearch
);
468 defaultEngine
->GetSubmission(NS_ConvertUTF8toUTF16(keyword
),
470 NS_LITERAL_STRING("keyword"),
471 getter_AddRefs(submission
));
474 nsCOMPtr
<nsIInputStream
> postData
;
475 submission
->GetPostData(getter_AddRefs(postData
));
477 postData
.forget(aPostData
);
478 } else if (postData
) {
479 // The submission specifies POST data (i.e. the search
480 // engine's "method" is POST), but our caller didn't allow
481 // passing post data back. No point passing back a URL that
482 // won't load properly.
483 return NS_ERROR_FAILURE
;
486 // This notification is meant for Firefox Health Report so it
487 // can increment counts from the search engine. The assumption
488 // here is that this keyword/submission will eventually result
489 // in a search. Since we only generate a URI here, there is the
490 // possibility we'll increment the counter without actually
491 // incurring a search. A robust solution would involve currying
492 // the search engine's name through various function calls.
493 nsCOMPtr
<nsIObserverService
> obsSvc
= mozilla::services::GetObserverService();
495 // Note that "keyword-search" refers to a search via the url
496 // bar, not a bookmarks keyword search.
497 obsSvc
->NotifyObservers(defaultEngine
, "keyword-search", NS_ConvertUTF8toUTF16(keyword
).get());
500 return submission
->GetUri(aURI
);
507 return NS_ERROR_NOT_AVAILABLE
;
510 bool nsDefaultURIFixup::MakeAlternateURI(nsIURI
*aURI
)
512 if (!Preferences::GetRootBranch())
516 if (!Preferences::GetBool("browser.fixup.alternate.enabled", true))
521 // Code only works for http. Not for any other protocol including https!
523 aURI
->SchemeIs("http", &isHttp
);
528 // Security - URLs with user / password info should NOT be fixed up
529 nsAutoCString userpass
;
530 aURI
->GetUserPass(userpass
);
531 if (!userpass
.IsEmpty()) {
535 nsAutoCString oldHost
;
536 nsAutoCString newHost
;
537 aURI
->GetHost(oldHost
);
541 nsReadingIterator
<char> iter
;
542 nsReadingIterator
<char> iterEnd
;
543 oldHost
.BeginReading(iter
);
544 oldHost
.EndReading(iterEnd
);
545 while (iter
!= iterEnd
) {
552 // Get the prefix and suffix to stick onto the new hostname. By default these
553 // are www. & .com but they could be any other value, e.g. www. & .org
555 nsAutoCString
prefix("www.");
556 nsAdoptingCString prefPrefix
=
557 Preferences::GetCString("browser.fixup.alternate.prefix");
560 prefix
.Assign(prefPrefix
);
563 nsAutoCString
suffix(".com");
564 nsAdoptingCString prefSuffix
=
565 Preferences::GetCString("browser.fixup.alternate.suffix");
568 suffix
.Assign(prefSuffix
);
573 newHost
.Assign(prefix
);
574 newHost
.Append(oldHost
);
575 newHost
.Append(suffix
);
577 else if (numDots
== 1)
579 if (!prefix
.IsEmpty() &&
580 oldHost
.EqualsIgnoreCase(prefix
.get(), prefix
.Length())) {
581 newHost
.Assign(oldHost
);
582 newHost
.Append(suffix
);
584 else if (!suffix
.IsEmpty()) {
585 newHost
.Assign(prefix
);
586 newHost
.Append(oldHost
);
600 if (newHost
.IsEmpty()) {
604 // Assign the new host string over the old one
605 aURI
->SetHost(newHost
);
610 * Check if the host name starts with ftp\d*\. and it's not directly followed
613 bool nsDefaultURIFixup::IsLikelyFTP(const nsCString
&aHostSpec
)
615 bool likelyFTP
= false;
616 if (aHostSpec
.EqualsIgnoreCase("ftp", 3)) {
617 nsACString::const_iterator iter
;
618 nsACString::const_iterator end
;
619 aHostSpec
.BeginReading(iter
);
620 aHostSpec
.EndReading(end
);
621 iter
.advance(3); // move past the "ftp" part
626 // now make sure the name has at least one more dot in it
638 else if (!nsCRT::IsAsciiDigit(*iter
)) {
647 nsresult
nsDefaultURIFixup::FileURIFixup(const nsACString
& aStringURI
,
650 nsAutoCString uriSpecOut
;
652 nsresult rv
= ConvertFileToStringURI(aStringURI
, uriSpecOut
);
653 if (NS_SUCCEEDED(rv
))
655 // if this is file url, uriSpecOut is already in FS charset
656 if(NS_SUCCEEDED(NS_NewURI(aURI
, uriSpecOut
.get(), nullptr)))
659 return NS_ERROR_FAILURE
;
662 nsresult
nsDefaultURIFixup::ConvertFileToStringURI(const nsACString
& aIn
,
665 bool attemptFixup
= false;
668 // Check for \ in the url-string or just a drive (PC)
669 if(kNotFound
!= aIn
.FindChar('\\') ||
670 (aIn
.Length() == 2 && (aIn
.Last() == ':' || aIn
.Last() == '|')))
674 #elif defined(XP_UNIX)
675 // Check if it starts with / (UNIX)
676 if(aIn
.First() == '/')
681 // Do nothing (All others for now)
686 // Test if this is a valid path by trying to create a local file
687 // object. The URL of that is returned if successful.
689 // NOTE: Please be sure to check that the call to NS_NewLocalFile
690 // rejects bad file paths when using this code on a new
693 nsCOMPtr
<nsIFile
> filePath
;
696 // this is not the real fix but a temporary fix
697 // in order to really fix the problem, we need to change the
698 // nsICmdLineService interface to use wstring to pass paramenters
699 // instead of string since path name and other argument could be
700 // in non ascii.(see bug 87127) Since it is too risky to make interface change right
701 // now, we decide not to do so now.
702 // Therefore, the aIn we receive here maybe already in damage form
703 // (e.g. treat every bytes as ISO-8859-1 and cast up to char16_t
704 // while the real data could be in file system charset )
705 // we choice the following logic which will work for most of the case.
706 // Case will still failed only if it meet ALL the following condiction:
707 // 1. running on CJK, Russian, or Greek system, and
708 // 2. user type it from URL bar
709 // 3. the file name contains character in the range of
710 // U+00A1-U+00FF but encode as different code point in file
711 // system charset (e.g. ACP on window)- this is very rare case
712 // We should remove this logic and convert to File system charset here
713 // once we change nsICmdLineService to use wstring and ensure
714 // all the Unicode data come in is correctly converted.
715 // XXXbz nsICmdLineService doesn't hand back unicode, so in some cases
716 // what we have is actually a "utf8" version of a "utf16" string that's
717 // actually byte-expanded native-encoding data. Someone upstream needs
718 // to stop using AssignWithConversion and do things correctly. See bug
719 // 58866 for what happens if we remove this
720 // PossiblyByteExpandedFileName check.
721 NS_ConvertUTF8toUTF16
in(aIn
);
722 if (PossiblyByteExpandedFileName(in
)) {
724 rv
= NS_NewNativeLocalFile(NS_LossyConvertUTF16toASCII(in
), false, getter_AddRefs(filePath
));
728 rv
= NS_NewLocalFile(in
, false, getter_AddRefs(filePath
));
731 if (NS_SUCCEEDED(rv
))
733 NS_GetURLSpecFromFile(filePath
, aOut
);
738 return NS_ERROR_FAILURE
;
743 nsDefaultURIFixup::FixupURIProtocol(const nsACString
& aURIString
,
744 nsDefaultURIFixupInfo
* aFixupInfo
,
747 nsAutoCString
uriString(aURIString
);
750 // Add ftp:// or http:// to front of url if it has no spec
756 // ftp4.no-scheme.com
757 // no-scheme.com/query?foo=http://www.foo.com
759 int32_t schemeDelim
= uriString
.Find("://",0);
760 int32_t firstDelim
= uriString
.FindCharInSet("/:");
761 if (schemeDelim
<= 0 ||
762 (firstDelim
!= -1 && schemeDelim
> firstDelim
)) {
764 int32_t hostPos
= uriString
.FindCharInSet("/:?#");
766 hostPos
= uriString
.Length();
769 nsAutoCString hostSpec
;
770 uriString
.Left(hostSpec
, hostPos
);
772 // insert url spec corresponding to host name
773 if (IsLikelyFTP(hostSpec
))
774 uriString
.InsertLiteral("ftp://", 0);
776 uriString
.InsertLiteral("http://", 0);
777 aFixupInfo
->mFixupChangedProtocol
= true;
778 } // end if checkprotocol
780 return NS_NewURI(aURI
, uriString
, nullptr);
784 bool nsDefaultURIFixup::PossiblyHostPortUrl(const nsACString
&aUrl
)
786 // Oh dear, the protocol is invalid. Test if the protocol might
787 // actually be a url without a protocol:
789 // http://www.faqs.org/rfcs/rfc1738.html
790 // http://www.faqs.org/rfcs/rfc2396.html
792 // e.g. Anything of the form:
794 // <hostname>:<port> or
795 // <hostname>:<port>/
797 // Where <hostname> is a string of alphanumeric characters and dashes
798 // separated by dots.
799 // and <port> is a 5 or less digits. This actually breaks the rfc2396
800 // definition of a scheme which allows dots in schemes.
803 // People expecting this to work with
804 // <user>:<password>@<host>:<port>/<url-path> will be disappointed!
806 // Note: Parser could be a lot tighter, tossing out silly hostnames
807 // such as those containing consecutive dots and so on.
809 // Read the hostname which should of the form
810 // [a-zA-Z0-9\-]+(\.[a-zA-Z0-9\-]+)*:
812 nsACString::const_iterator iterBegin
;
813 nsACString::const_iterator iterEnd
;
814 aUrl
.BeginReading(iterBegin
);
815 aUrl
.EndReading(iterEnd
);
816 nsACString::const_iterator iter
= iterBegin
;
818 while (iter
!= iterEnd
)
820 uint32_t chunkSize
= 0;
821 // Parse a chunk of the address
822 while (iter
!= iterEnd
&&
824 nsCRT::IsAsciiAlpha(*iter
) ||
825 nsCRT::IsAsciiDigit(*iter
)))
830 if (chunkSize
== 0 || iter
== iterEnd
)
836 // Go onto checking the for the digits
841 // Whatever it is, it ain't a hostname!
848 // No point continuing since there is no colon
853 // Count the number of digits after the colon and before the
854 // next forward slash (or end of string)
856 uint32_t digitCount
= 0;
857 while (iter
!= iterEnd
&& digitCount
<= 5)
859 if (nsCRT::IsAsciiDigit(*iter
))
863 else if (*iter
== '/')
869 // Whatever it is, it ain't a port!
874 if (digitCount
== 0 || digitCount
> 5)
876 // No digits or more digits than a port would have.
880 // Yes, it's possibly a host:port url
884 bool nsDefaultURIFixup::PossiblyByteExpandedFileName(const nsAString
& aIn
)
886 // XXXXX HACK XXXXX : please don't copy this code.
887 // There are cases where aIn contains the locale byte chars padded to short
888 // (thus the name "ByteExpanded"); whereas other cases
889 // have proper Unicode code points.
890 // This is a temporary fix. Please refer to 58866, 86948
892 nsReadingIterator
<char16_t
> iter
;
893 nsReadingIterator
<char16_t
> iterEnd
;
894 aIn
.BeginReading(iter
);
895 aIn
.EndReading(iterEnd
);
896 while (iter
!= iterEnd
)
898 if (*iter
>= 0x0080 && *iter
<= 0x00FF)
905 void nsDefaultURIFixup::KeywordURIFixup(const nsACString
& aURIString
,
906 nsDefaultURIFixupInfo
* aFixupInfo
,
907 nsIInputStream
**aPostData
)
909 // These are keyword formatted strings
911 // "what is mozilla?"
912 // "docshell site:mozilla.org" - has no dot/colon in the first space-separated substring
913 // "?mozilla" - anything that begins with a question mark
914 // "?site:mozilla.org docshell"
915 // Things that have a quote before the first dot/colon
916 // "mozilla" - checked against a whitelist to see if it's a host or not
917 // ".mozilla", "mozilla." - ditto
919 // These are not keyword formatted strings
920 // "www.blah.com" - first space-separated substring contains a dot, doesn't start with "?"
921 // "www.blah.com stuff"
922 // "nonQualifiedHost:80" - first space-separated substring contains a colon, doesn't start with "?"
923 // "nonQualifiedHost:80 args"
924 // "nonQualifiedHost?"
925 // "nonQualifiedHost?args"
926 // "nonQualifiedHost?some args"
929 // Note: uint32_t(kNotFound) is greater than any actual location
930 // in practice. So if we cast all locations to uint32_t, then a <
931 // b guarantees that either b is kNotFound and a is found, or both
932 // are found and a found before b.
933 uint32_t dotLoc
= uint32_t(aURIString
.FindChar('.'));
934 nsAutoCString
tmpURIString(aURIString
);
935 uint32_t lastDotLoc
= uint32_t(tmpURIString
.RFindChar('.'));
936 uint32_t colonLoc
= uint32_t(aURIString
.FindChar(':'));
937 uint32_t spaceLoc
= uint32_t(aURIString
.FindChar(' '));
939 // Treat this as not found
940 spaceLoc
= uint32_t(kNotFound
);
942 uint32_t qMarkLoc
= uint32_t(aURIString
.FindChar('?'));
943 uint32_t quoteLoc
= std::min(uint32_t(aURIString
.FindChar('"')),
944 uint32_t(aURIString
.FindChar('\'')));
947 // We do keyword lookups if a space or quote preceded the dot, colon
948 // or question mark (or if the latter were not found):
949 if (((spaceLoc
< dotLoc
|| quoteLoc
< dotLoc
) &&
950 (spaceLoc
< colonLoc
|| quoteLoc
< colonLoc
) &&
951 (spaceLoc
< qMarkLoc
|| quoteLoc
< qMarkLoc
)) ||
954 rv
= KeywordToURI(aFixupInfo
->mOriginalInput
, aPostData
,
955 getter_AddRefs(aFixupInfo
->mPreferredURI
));
956 if (NS_SUCCEEDED(rv
) && aFixupInfo
->mPreferredURI
)
958 aFixupInfo
->mFixupUsedKeyword
= true;
961 // ... or if there is no question mark or colon, and there is either no
962 // dot, or exactly 1 and it is the first or last character of the input:
963 else if ((dotLoc
== uint32_t(kNotFound
) ||
964 (dotLoc
== lastDotLoc
&& (dotLoc
== 0 || dotLoc
== aURIString
.Length() - 1))) &&
965 colonLoc
== uint32_t(kNotFound
) && qMarkLoc
== uint32_t(kNotFound
))
967 nsAutoCString asciiHost
;
968 if (aFixupInfo
->mFixedURI
&&
969 NS_SUCCEEDED(aFixupInfo
->mFixedURI
->GetAsciiHost(asciiHost
)) &&
970 !asciiHost
.IsEmpty())
972 // Check if this domain is whitelisted as an actual
973 // domain (which will prevent a keyword query)
974 // NB: any processing of the host here should stay in sync with
975 // code in the front-end(s) that set the pref.
976 nsAutoCString
pref("browser.fixup.domainwhitelist.");
977 if (dotLoc
== aURIString
.Length() - 1) {
978 pref
.Append(Substring(asciiHost
, 0, asciiHost
.Length() - 1));
980 pref
.Append(asciiHost
);
982 if (Preferences::GetBool(pref
.get(), false))
987 // If we get here, we don't have a valid URI, or we did but the
988 // host is not whitelisted, so we do a keyword search *anyway*:
989 rv
= KeywordToURI(aFixupInfo
->mOriginalInput
, aPostData
,
990 getter_AddRefs(aFixupInfo
->mPreferredURI
));
991 if (NS_SUCCEEDED(rv
) && aFixupInfo
->mPreferredURI
)
993 aFixupInfo
->mFixupUsedKeyword
= true;
999 nsresult
NS_NewURIFixup(nsIURIFixup
**aURIFixup
)
1001 nsDefaultURIFixup
*fixup
= new nsDefaultURIFixup
;
1002 if (fixup
== nullptr)
1004 return NS_ERROR_OUT_OF_MEMORY
;
1006 return fixup
->QueryInterface(NS_GET_IID(nsIURIFixup
), (void **) aURIFixup
);
1010 /* Implementation of nsIURIFixupInfo */
1011 NS_IMPL_ISUPPORTS(nsDefaultURIFixupInfo
, nsIURIFixupInfo
)
1013 nsDefaultURIFixupInfo::nsDefaultURIFixupInfo(const nsACString
& aOriginalInput
):
1014 mFixupUsedKeyword(false),
1015 mFixupChangedProtocol(false),
1016 mFixupCreatedAlternateURI(false)
1018 mOriginalInput
= aOriginalInput
;
1022 nsDefaultURIFixupInfo::~nsDefaultURIFixupInfo()
1027 nsDefaultURIFixupInfo::GetConsumer(nsISupports
** aConsumer
)
1029 *aConsumer
= mConsumer
;
1030 NS_IF_ADDREF(*aConsumer
);
1035 nsDefaultURIFixupInfo::SetConsumer(nsISupports
* aConsumer
)
1037 mConsumer
= aConsumer
;
1042 nsDefaultURIFixupInfo::GetPreferredURI(nsIURI
** aPreferredURI
)
1044 *aPreferredURI
= mPreferredURI
;
1045 NS_IF_ADDREF(*aPreferredURI
);
1050 nsDefaultURIFixupInfo::GetFixedURI(nsIURI
** aFixedURI
)
1052 *aFixedURI
= mFixedURI
;
1053 NS_IF_ADDREF(*aFixedURI
);
1058 nsDefaultURIFixupInfo::GetFixupUsedKeyword(bool* aOut
)
1060 *aOut
= mFixupUsedKeyword
;
1065 nsDefaultURIFixupInfo::GetFixupChangedProtocol(bool* aOut
)
1067 *aOut
= mFixupChangedProtocol
;
1072 nsDefaultURIFixupInfo::GetFixupCreatedAlternateURI(bool* aOut
)
1074 *aOut
= mFixupCreatedAlternateURI
;
1079 nsDefaultURIFixupInfo::GetOriginalInput(nsACString
& aInput
)
1081 aInput
= mOriginalInput
;