Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 *
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/. */
7 #include "nsNetUtil.h"
8 #include "nsCRT.h"
10 #include "nsIFile.h"
11 #include <algorithm>
13 #ifdef MOZ_TOOLKIT_SEARCH
14 #include "nsIBrowserSearchService.h"
15 #endif
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 using namespace mozilla;
28 /* Implementation file */
29 NS_IMPL_ISUPPORTS(nsDefaultURIFixup, nsIURIFixup)
31 static bool sInitializedPrefCaches = false;
32 static bool sFixTypos = true;
34 nsDefaultURIFixup::nsDefaultURIFixup()
35 {
36 /* member initializers and constructor code */
37 }
40 nsDefaultURIFixup::~nsDefaultURIFixup()
41 {
42 /* destructor code */
43 }
45 /* nsIURI createExposableURI (in nsIURI aURI); */
46 NS_IMETHODIMP
47 nsDefaultURIFixup::CreateExposableURI(nsIURI *aURI, nsIURI **aReturn)
48 {
49 NS_ENSURE_ARG_POINTER(aURI);
50 NS_ENSURE_ARG_POINTER(aReturn);
52 bool isWyciwyg = false;
53 aURI->SchemeIs("wyciwyg", &isWyciwyg);
55 nsAutoCString userPass;
56 aURI->GetUserPass(userPass);
58 // most of the time we can just AddRef and return
59 if (!isWyciwyg && userPass.IsEmpty())
60 {
61 *aReturn = aURI;
62 NS_ADDREF(*aReturn);
63 return NS_OK;
64 }
66 // Rats, we have to massage the URI
67 nsCOMPtr<nsIURI> uri;
68 if (isWyciwyg)
69 {
70 nsAutoCString path;
71 nsresult rv = aURI->GetPath(path);
72 NS_ENSURE_SUCCESS(rv, rv);
74 uint32_t pathLength = path.Length();
75 if (pathLength <= 2)
76 {
77 return NS_ERROR_FAILURE;
78 }
80 // Path is of the form "//123/http://foo/bar", with a variable number of digits.
81 // To figure out where the "real" URL starts, search path for a '/', starting at
82 // the third character.
83 int32_t slashIndex = path.FindChar('/', 2);
84 if (slashIndex == kNotFound)
85 {
86 return NS_ERROR_FAILURE;
87 }
89 // Get the charset of the original URI so we can pass it to our fixed up URI.
90 nsAutoCString charset;
91 aURI->GetOriginCharset(charset);
93 rv = NS_NewURI(getter_AddRefs(uri),
94 Substring(path, slashIndex + 1, pathLength - slashIndex - 1),
95 charset.get());
96 NS_ENSURE_SUCCESS(rv, rv);
97 }
98 else
99 {
100 // clone the URI so zapping user:pass doesn't change the original
101 nsresult rv = aURI->Clone(getter_AddRefs(uri));
102 NS_ENSURE_SUCCESS(rv, rv);
103 }
105 // hide user:pass unless overridden by pref
106 if (Preferences::GetBool("browser.fixup.hide_user_pass", true))
107 {
108 uri->SetUserPass(EmptyCString());
109 }
111 // return the fixed-up URI
112 *aReturn = uri;
113 NS_ADDREF(*aReturn);
114 return NS_OK;
115 }
117 /* nsIURI createFixupURI (in nsAUTF8String aURIText, in unsigned long aFixupFlags); */
118 NS_IMETHODIMP
119 nsDefaultURIFixup::CreateFixupURI(const nsACString& aStringURI, uint32_t aFixupFlags,
120 nsIInputStream **aPostData, nsIURI **aURI)
121 {
122 NS_ENSURE_ARG(!aStringURI.IsEmpty());
123 NS_ENSURE_ARG_POINTER(aURI);
125 nsresult rv;
126 *aURI = nullptr;
128 nsAutoCString uriString(aStringURI);
129 uriString.Trim(" "); // Cleanup the empty spaces that might be on each end.
131 // Eliminate embedded newlines, which single-line text fields now allow:
132 uriString.StripChars("\r\n");
134 NS_ENSURE_TRUE(!uriString.IsEmpty(), NS_ERROR_FAILURE);
136 nsCOMPtr<nsIIOService> ioService = do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
137 NS_ENSURE_SUCCESS(rv, rv);
138 nsAutoCString scheme;
139 ioService->ExtractScheme(aStringURI, scheme);
141 // View-source is a pseudo scheme. We're interested in fixing up the stuff
142 // after it. The easiest way to do that is to call this method again with the
143 // "view-source:" lopped off and then prepend it again afterwards.
145 if (scheme.LowerCaseEqualsLiteral("view-source"))
146 {
147 nsCOMPtr<nsIURI> uri;
148 uint32_t newFixupFlags = aFixupFlags & ~FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
150 rv = CreateFixupURI(Substring(uriString,
151 sizeof("view-source:") - 1,
152 uriString.Length() -
153 (sizeof("view-source:") - 1)),
154 newFixupFlags, aPostData, getter_AddRefs(uri));
155 if (NS_FAILED(rv))
156 return NS_ERROR_FAILURE;
157 nsAutoCString spec;
158 uri->GetSpec(spec);
159 uriString.Assign(NS_LITERAL_CSTRING("view-source:") + spec);
160 }
161 else {
162 // Check for if it is a file URL
163 FileURIFixup(uriString, aURI);
164 if(*aURI)
165 return NS_OK;
167 #if defined(XP_WIN)
168 // Not a file URL, so translate '\' to '/' for convenience in the common protocols
169 // e.g. catch
170 //
171 // http:\\broken.com\address
172 // http:\\broken.com/blah
173 // broken.com\blah
174 //
175 // Code will also do partial fix up the following urls
176 //
177 // http:\\broken.com\address/somewhere\image.jpg (stops at first forward slash)
178 // http:\\broken.com\blah?arg=somearg\foo.jpg (stops at question mark)
179 // http:\\broken.com#odd\ref (stops at hash)
180 //
181 if (scheme.IsEmpty() ||
182 scheme.LowerCaseEqualsLiteral("http") ||
183 scheme.LowerCaseEqualsLiteral("https") ||
184 scheme.LowerCaseEqualsLiteral("ftp"))
185 {
186 // Walk the string replacing backslashes with forward slashes until
187 // the end is reached, or a question mark, or a hash, or a forward
188 // slash. The forward slash test is to stop before trampling over
189 // URIs which legitimately contain a mix of both forward and
190 // backward slashes.
191 nsAutoCString::iterator start;
192 nsAutoCString::iterator end;
193 uriString.BeginWriting(start);
194 uriString.EndWriting(end);
195 while (start != end) {
196 if (*start == '?' || *start == '#' || *start == '/')
197 break;
198 if (*start == '\\')
199 *start = '/';
200 ++start;
201 }
202 }
203 #endif
204 }
206 if (!sInitializedPrefCaches) {
207 // Check if we want to fix up common scheme typos.
208 rv = Preferences::AddBoolVarCache(&sFixTypos,
209 "browser.fixup.typo.scheme",
210 sFixTypos);
211 MOZ_ASSERT(NS_SUCCEEDED(rv),
212 "Failed to observe \"browser.fixup.typo.scheme\"");
213 sInitializedPrefCaches = true;
214 }
216 // Fix up common scheme typos.
217 if (sFixTypos && (aFixupFlags & FIXUP_FLAG_FIX_SCHEME_TYPOS)) {
219 // Fast-path for common cases.
220 if (scheme.IsEmpty() ||
221 scheme.LowerCaseEqualsLiteral("http") ||
222 scheme.LowerCaseEqualsLiteral("https") ||
223 scheme.LowerCaseEqualsLiteral("ftp") ||
224 scheme.LowerCaseEqualsLiteral("file")) {
225 // Do nothing.
226 } else if (scheme.LowerCaseEqualsLiteral("ttp")) {
227 // ttp -> http.
228 uriString.Replace(0, 3, "http");
229 scheme.AssignLiteral("http");
230 } else if (scheme.LowerCaseEqualsLiteral("ttps")) {
231 // ttps -> https.
232 uriString.Replace(0, 4, "https");
233 scheme.AssignLiteral("https");
234 } else if (scheme.LowerCaseEqualsLiteral("tps")) {
235 // tps -> https.
236 uriString.Replace(0, 3, "https");
237 scheme.AssignLiteral("https");
238 } else if (scheme.LowerCaseEqualsLiteral("ps")) {
239 // ps -> https.
240 uriString.Replace(0, 2, "https");
241 scheme.AssignLiteral("https");
242 } else if (scheme.LowerCaseEqualsLiteral("ile")) {
243 // ile -> file.
244 uriString.Replace(0, 3, "file");
245 scheme.AssignLiteral("file");
246 } else if (scheme.LowerCaseEqualsLiteral("le")) {
247 // le -> file.
248 uriString.Replace(0, 2, "file");
249 scheme.AssignLiteral("file");
250 }
251 }
253 // Now we need to check whether "scheme" is something we don't
254 // really know about.
255 nsCOMPtr<nsIProtocolHandler> ourHandler, extHandler;
257 ioService->GetProtocolHandler(scheme.get(), getter_AddRefs(ourHandler));
258 extHandler = do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX"default");
260 if (ourHandler != extHandler || !PossiblyHostPortUrl(uriString)) {
261 // Just try to create an URL out of it
262 rv = NS_NewURI(aURI, uriString, nullptr);
264 if (!*aURI && rv != NS_ERROR_MALFORMED_URI) {
265 return rv;
266 }
267 }
269 if (*aURI) {
270 if (aFixupFlags & FIXUP_FLAGS_MAKE_ALTERNATE_URI)
271 MakeAlternateURI(*aURI);
272 return NS_OK;
273 }
275 // See if it is a keyword
276 // Test whether keywords need to be fixed up
277 bool fixupKeywords = false;
278 if (aFixupFlags & FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP) {
279 nsresult rv = Preferences::GetBool("keyword.enabled", &fixupKeywords);
280 NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
281 if (fixupKeywords)
282 {
283 KeywordURIFixup(uriString, aPostData, aURI);
284 if(*aURI)
285 return NS_OK;
286 }
287 }
289 // Prune duff protocol schemes
290 //
291 // ://totallybroken.url.com
292 // //shorthand.url.com
293 //
294 if (StringBeginsWith(uriString, NS_LITERAL_CSTRING("://")))
295 {
296 uriString = StringTail(uriString, uriString.Length() - 3);
297 }
298 else if (StringBeginsWith(uriString, NS_LITERAL_CSTRING("//")))
299 {
300 uriString = StringTail(uriString, uriString.Length() - 2);
301 }
303 // Add ftp:// or http:// to front of url if it has no spec
304 //
305 // Should fix:
306 //
307 // no-scheme.com
308 // ftp.no-scheme.com
309 // ftp4.no-scheme.com
310 // no-scheme.com/query?foo=http://www.foo.com
311 //
312 int32_t schemeDelim = uriString.Find("://",0);
313 int32_t firstDelim = uriString.FindCharInSet("/:");
314 if (schemeDelim <= 0 ||
315 (firstDelim != -1 && schemeDelim > firstDelim)) {
316 // find host name
317 int32_t hostPos = uriString.FindCharInSet("/:?#");
318 if (hostPos == -1)
319 hostPos = uriString.Length();
321 // extract host name
322 nsAutoCString 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);
330 } // end if checkprotocol
332 rv = NS_NewURI(aURI, uriString, nullptr);
334 // Did the caller want us to try an alternative URI?
335 // If so, attempt to fixup http://foo into http://www.foo.com
337 if (*aURI && aFixupFlags & FIXUP_FLAGS_MAKE_ALTERNATE_URI) {
338 MakeAlternateURI(*aURI);
339 }
341 // If we still haven't been able to construct a valid URI, try to force a
342 // keyword match. This catches search strings with '.' or ':' in them.
343 if (!*aURI && fixupKeywords)
344 {
345 KeywordToURI(aStringURI, aPostData, aURI);
346 if(*aURI)
347 return NS_OK;
348 }
350 return rv;
351 }
353 NS_IMETHODIMP nsDefaultURIFixup::KeywordToURI(const nsACString& aKeyword,
354 nsIInputStream **aPostData,
355 nsIURI **aURI)
356 {
357 *aURI = nullptr;
358 if (aPostData) {
359 *aPostData = nullptr;
360 }
361 NS_ENSURE_STATE(Preferences::GetRootBranch());
363 // Strip leading "?" and leading/trailing spaces from aKeyword
364 nsAutoCString keyword(aKeyword);
365 if (StringBeginsWith(keyword, NS_LITERAL_CSTRING("?"))) {
366 keyword.Cut(0, 1);
367 }
368 keyword.Trim(" ");
370 if (XRE_GetProcessType() == GeckoProcessType_Content) {
371 dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
372 if (!contentChild) {
373 return NS_ERROR_NOT_AVAILABLE;
374 }
376 ipc::OptionalInputStreamParams postData;
377 ipc::OptionalURIParams uri;
378 if (!contentChild->SendKeywordToURI(keyword, &postData, &uri)) {
379 return NS_ERROR_FAILURE;
380 }
382 if (aPostData) {
383 nsTArray<ipc::FileDescriptor> fds;
384 nsCOMPtr<nsIInputStream> temp = DeserializeInputStream(postData, fds);
385 temp.forget(aPostData);
387 MOZ_ASSERT(fds.IsEmpty());
388 }
390 nsCOMPtr<nsIURI> temp = DeserializeURI(uri);
391 temp.forget(aURI);
392 return NS_OK;
393 }
395 #ifdef MOZ_TOOLKIT_SEARCH
396 // Try falling back to the search service's default search engine
397 nsCOMPtr<nsIBrowserSearchService> searchSvc = do_GetService("@mozilla.org/browser/search-service;1");
398 if (searchSvc) {
399 nsCOMPtr<nsISearchEngine> defaultEngine;
400 searchSvc->GetDefaultEngine(getter_AddRefs(defaultEngine));
401 if (defaultEngine) {
402 nsCOMPtr<nsISearchSubmission> submission;
403 // We allow default search plugins to specify alternate
404 // parameters that are specific to keyword searches.
405 NS_NAMED_LITERAL_STRING(mozKeywordSearch, "application/x-moz-keywordsearch");
406 bool supportsResponseType = false;
407 defaultEngine->SupportsResponseType(mozKeywordSearch, &supportsResponseType);
408 if (supportsResponseType)
409 defaultEngine->GetSubmission(NS_ConvertUTF8toUTF16(keyword),
410 mozKeywordSearch,
411 NS_LITERAL_STRING("keyword"),
412 getter_AddRefs(submission));
413 else
414 defaultEngine->GetSubmission(NS_ConvertUTF8toUTF16(keyword),
415 EmptyString(),
416 NS_LITERAL_STRING("keyword"),
417 getter_AddRefs(submission));
418 if (submission) {
419 nsCOMPtr<nsIInputStream> postData;
420 submission->GetPostData(getter_AddRefs(postData));
421 if (aPostData) {
422 postData.forget(aPostData);
423 } else if (postData) {
424 // The submission specifies POST data (i.e. the search
425 // engine's "method" is POST), but our caller didn't allow
426 // passing post data back. No point passing back a URL that
427 // won't load properly.
428 return NS_ERROR_FAILURE;
429 }
431 // This notification is meant for Firefox Health Report so it
432 // can increment counts from the search engine. The assumption
433 // here is that this keyword/submission will eventually result
434 // in a search. Since we only generate a URI here, there is the
435 // possibility we'll increment the counter without actually
436 // incurring a search. A robust solution would involve currying
437 // the search engine's name through various function calls.
438 nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
439 if (obsSvc) {
440 // Note that "keyword-search" refers to a search via the url
441 // bar, not a bookmarks keyword search.
442 obsSvc->NotifyObservers(defaultEngine, "keyword-search", NS_ConvertUTF8toUTF16(keyword).get());
443 }
445 return submission->GetUri(aURI);
446 }
447 }
448 }
449 #endif
451 // out of options
452 return NS_ERROR_NOT_AVAILABLE;
453 }
455 bool nsDefaultURIFixup::MakeAlternateURI(nsIURI *aURI)
456 {
457 if (!Preferences::GetRootBranch())
458 {
459 return false;
460 }
461 if (!Preferences::GetBool("browser.fixup.alternate.enabled", true))
462 {
463 return false;
464 }
466 // Code only works for http. Not for any other protocol including https!
467 bool isHttp = false;
468 aURI->SchemeIs("http", &isHttp);
469 if (!isHttp) {
470 return false;
471 }
473 // Security - URLs with user / password info should NOT be fixed up
474 nsAutoCString userpass;
475 aURI->GetUserPass(userpass);
476 if (!userpass.IsEmpty()) {
477 return false;
478 }
480 nsAutoCString oldHost;
481 nsAutoCString newHost;
482 aURI->GetHost(oldHost);
484 // Count the dots
485 int32_t numDots = 0;
486 nsReadingIterator<char> iter;
487 nsReadingIterator<char> iterEnd;
488 oldHost.BeginReading(iter);
489 oldHost.EndReading(iterEnd);
490 while (iter != iterEnd) {
491 if (*iter == '.')
492 numDots++;
493 ++iter;
494 }
497 // Get the prefix and suffix to stick onto the new hostname. By default these
498 // are www. & .com but they could be any other value, e.g. www. & .org
500 nsAutoCString prefix("www.");
501 nsAdoptingCString prefPrefix =
502 Preferences::GetCString("browser.fixup.alternate.prefix");
503 if (prefPrefix)
504 {
505 prefix.Assign(prefPrefix);
506 }
508 nsAutoCString suffix(".com");
509 nsAdoptingCString prefSuffix =
510 Preferences::GetCString("browser.fixup.alternate.suffix");
511 if (prefSuffix)
512 {
513 suffix.Assign(prefSuffix);
514 }
516 if (numDots == 0)
517 {
518 newHost.Assign(prefix);
519 newHost.Append(oldHost);
520 newHost.Append(suffix);
521 }
522 else if (numDots == 1)
523 {
524 if (!prefix.IsEmpty() &&
525 oldHost.EqualsIgnoreCase(prefix.get(), prefix.Length())) {
526 newHost.Assign(oldHost);
527 newHost.Append(suffix);
528 }
529 else if (!suffix.IsEmpty()) {
530 newHost.Assign(prefix);
531 newHost.Append(oldHost);
532 }
533 else
534 {
535 // Do nothing
536 return false;
537 }
538 }
539 else
540 {
541 // Do nothing
542 return false;
543 }
545 if (newHost.IsEmpty()) {
546 return false;
547 }
549 // Assign the new host string over the old one
550 aURI->SetHost(newHost);
551 return true;
552 }
554 /**
555 * Check if the host name starts with ftp\d*\. and it's not directly followed
556 * by the tld.
557 */
558 bool nsDefaultURIFixup::IsLikelyFTP(const nsCString &aHostSpec)
559 {
560 bool likelyFTP = false;
561 if (aHostSpec.EqualsIgnoreCase("ftp", 3)) {
562 nsACString::const_iterator iter;
563 nsACString::const_iterator end;
564 aHostSpec.BeginReading(iter);
565 aHostSpec.EndReading(end);
566 iter.advance(3); // move past the "ftp" part
568 while (iter != end)
569 {
570 if (*iter == '.') {
571 // now make sure the name has at least one more dot in it
572 ++iter;
573 while (iter != end)
574 {
575 if (*iter == '.') {
576 likelyFTP = true;
577 break;
578 }
579 ++iter;
580 }
581 break;
582 }
583 else if (!nsCRT::IsAsciiDigit(*iter)) {
584 break;
585 }
586 ++iter;
587 }
588 }
589 return likelyFTP;
590 }
592 nsresult nsDefaultURIFixup::FileURIFixup(const nsACString& aStringURI,
593 nsIURI** aURI)
594 {
595 nsAutoCString uriSpecOut;
597 nsresult rv = ConvertFileToStringURI(aStringURI, uriSpecOut);
598 if (NS_SUCCEEDED(rv))
599 {
600 // if this is file url, uriSpecOut is already in FS charset
601 if(NS_SUCCEEDED(NS_NewURI(aURI, uriSpecOut.get(), nullptr)))
602 return NS_OK;
603 }
604 return NS_ERROR_FAILURE;
605 }
607 nsresult nsDefaultURIFixup::ConvertFileToStringURI(const nsACString& aIn,
608 nsCString& aOut)
609 {
610 bool attemptFixup = false;
612 #if defined(XP_WIN)
613 // Check for \ in the url-string or just a drive (PC)
614 if(kNotFound != aIn.FindChar('\\') ||
615 (aIn.Length() == 2 && (aIn.Last() == ':' || aIn.Last() == '|')))
616 {
617 attemptFixup = true;
618 }
619 #elif defined(XP_UNIX)
620 // Check if it starts with / (UNIX)
621 if(aIn.First() == '/')
622 {
623 attemptFixup = true;
624 }
625 #else
626 // Do nothing (All others for now)
627 #endif
629 if (attemptFixup)
630 {
631 // Test if this is a valid path by trying to create a local file
632 // object. The URL of that is returned if successful.
634 // NOTE: Please be sure to check that the call to NS_NewLocalFile
635 // rejects bad file paths when using this code on a new
636 // platform.
638 nsCOMPtr<nsIFile> filePath;
639 nsresult rv;
641 // this is not the real fix but a temporary fix
642 // in order to really fix the problem, we need to change the
643 // nsICmdLineService interface to use wstring to pass paramenters
644 // instead of string since path name and other argument could be
645 // in non ascii.(see bug 87127) Since it is too risky to make interface change right
646 // now, we decide not to do so now.
647 // Therefore, the aIn we receive here maybe already in damage form
648 // (e.g. treat every bytes as ISO-8859-1 and cast up to char16_t
649 // while the real data could be in file system charset )
650 // we choice the following logic which will work for most of the case.
651 // Case will still failed only if it meet ALL the following condiction:
652 // 1. running on CJK, Russian, or Greek system, and
653 // 2. user type it from URL bar
654 // 3. the file name contains character in the range of
655 // U+00A1-U+00FF but encode as different code point in file
656 // system charset (e.g. ACP on window)- this is very rare case
657 // We should remove this logic and convert to File system charset here
658 // once we change nsICmdLineService to use wstring and ensure
659 // all the Unicode data come in is correctly converted.
660 // XXXbz nsICmdLineService doesn't hand back unicode, so in some cases
661 // what we have is actually a "utf8" version of a "utf16" string that's
662 // actually byte-expanded native-encoding data. Someone upstream needs
663 // to stop using AssignWithConversion and do things correctly. See bug
664 // 58866 for what happens if we remove this
665 // PossiblyByteExpandedFileName check.
666 NS_ConvertUTF8toUTF16 in(aIn);
667 if (PossiblyByteExpandedFileName(in)) {
668 // removes high byte
669 rv = NS_NewNativeLocalFile(NS_LossyConvertUTF16toASCII(in), false, getter_AddRefs(filePath));
670 }
671 else {
672 // input is unicode
673 rv = NS_NewLocalFile(in, false, getter_AddRefs(filePath));
674 }
676 if (NS_SUCCEEDED(rv))
677 {
678 NS_GetURLSpecFromFile(filePath, aOut);
679 return NS_OK;
680 }
681 }
683 return NS_ERROR_FAILURE;
684 }
686 bool nsDefaultURIFixup::PossiblyHostPortUrl(const nsACString &aUrl)
687 {
688 // Oh dear, the protocol is invalid. Test if the protocol might
689 // actually be a url without a protocol:
690 //
691 // http://www.faqs.org/rfcs/rfc1738.html
692 // http://www.faqs.org/rfcs/rfc2396.html
693 //
694 // e.g. Anything of the form:
695 //
696 // <hostname>:<port> or
697 // <hostname>:<port>/
698 //
699 // Where <hostname> is a string of alphanumeric characters and dashes
700 // separated by dots.
701 // and <port> is a 5 or less digits. This actually breaks the rfc2396
702 // definition of a scheme which allows dots in schemes.
703 //
704 // Note:
705 // People expecting this to work with
706 // <user>:<password>@<host>:<port>/<url-path> will be disappointed!
707 //
708 // Note: Parser could be a lot tighter, tossing out silly hostnames
709 // such as those containing consecutive dots and so on.
711 // Read the hostname which should of the form
712 // [a-zA-Z0-9\-]+(\.[a-zA-Z0-9\-]+)*:
714 nsACString::const_iterator iterBegin;
715 nsACString::const_iterator iterEnd;
716 aUrl.BeginReading(iterBegin);
717 aUrl.EndReading(iterEnd);
718 nsACString::const_iterator iter = iterBegin;
720 while (iter != iterEnd)
721 {
722 uint32_t chunkSize = 0;
723 // Parse a chunk of the address
724 while (iter != iterEnd &&
725 (*iter == '-' ||
726 nsCRT::IsAsciiAlpha(*iter) ||
727 nsCRT::IsAsciiDigit(*iter)))
728 {
729 ++chunkSize;
730 ++iter;
731 }
732 if (chunkSize == 0 || iter == iterEnd)
733 {
734 return false;
735 }
736 if (*iter == ':')
737 {
738 // Go onto checking the for the digits
739 break;
740 }
741 if (*iter != '.')
742 {
743 // Whatever it is, it ain't a hostname!
744 return false;
745 }
746 ++iter;
747 }
748 if (iter == iterEnd)
749 {
750 // No point continuing since there is no colon
751 return false;
752 }
753 ++iter;
755 // Count the number of digits after the colon and before the
756 // next forward slash (or end of string)
758 uint32_t digitCount = 0;
759 while (iter != iterEnd && digitCount <= 5)
760 {
761 if (nsCRT::IsAsciiDigit(*iter))
762 {
763 digitCount++;
764 }
765 else if (*iter == '/')
766 {
767 break;
768 }
769 else
770 {
771 // Whatever it is, it ain't a port!
772 return false;
773 }
774 ++iter;
775 }
776 if (digitCount == 0 || digitCount > 5)
777 {
778 // No digits or more digits than a port would have.
779 return false;
780 }
782 // Yes, it's possibly a host:port url
783 return true;
784 }
786 bool nsDefaultURIFixup::PossiblyByteExpandedFileName(const nsAString& aIn)
787 {
788 // XXXXX HACK XXXXX : please don't copy this code.
789 // There are cases where aIn contains the locale byte chars padded to short
790 // (thus the name "ByteExpanded"); whereas other cases
791 // have proper Unicode code points.
792 // This is a temporary fix. Please refer to 58866, 86948
794 nsReadingIterator<char16_t> iter;
795 nsReadingIterator<char16_t> iterEnd;
796 aIn.BeginReading(iter);
797 aIn.EndReading(iterEnd);
798 while (iter != iterEnd)
799 {
800 if (*iter >= 0x0080 && *iter <= 0x00FF)
801 return true;
802 ++iter;
803 }
804 return false;
805 }
807 void nsDefaultURIFixup::KeywordURIFixup(const nsACString & aURIString,
808 nsIInputStream **aPostData,
809 nsIURI** aURI)
810 {
811 // These are keyword formatted strings
812 // "what is mozilla"
813 // "what is mozilla?"
814 // "docshell site:mozilla.org" - has no dot/colon in the first space-separated substring
815 // "?mozilla" - anything that begins with a question mark
816 // "?site:mozilla.org docshell"
817 // Things that have a quote before the first dot/colon
819 // These are not keyword formatted strings
820 // "www.blah.com" - first space-separated substring contains a dot, doesn't start with "?"
821 // "www.blah.com stuff"
822 // "nonQualifiedHost:80" - first space-separated substring contains a colon, doesn't start with "?"
823 // "nonQualifiedHost:80 args"
824 // "nonQualifiedHost?"
825 // "nonQualifiedHost?args"
826 // "nonQualifiedHost?some args"
828 // Note: uint32_t(kNotFound) is greater than any actual location
829 // in practice. So if we cast all locations to uint32_t, then a <
830 // b guarantees that either b is kNotFound and a is found, or both
831 // are found and a found before b.
832 uint32_t dotLoc = uint32_t(aURIString.FindChar('.'));
833 uint32_t colonLoc = uint32_t(aURIString.FindChar(':'));
834 uint32_t spaceLoc = uint32_t(aURIString.FindChar(' '));
835 if (spaceLoc == 0) {
836 // Treat this as not found
837 spaceLoc = uint32_t(kNotFound);
838 }
839 uint32_t qMarkLoc = uint32_t(aURIString.FindChar('?'));
840 uint32_t quoteLoc = std::min(uint32_t(aURIString.FindChar('"')),
841 uint32_t(aURIString.FindChar('\'')));
843 if (((spaceLoc < dotLoc || quoteLoc < dotLoc) &&
844 (spaceLoc < colonLoc || quoteLoc < colonLoc) &&
845 (spaceLoc < qMarkLoc || quoteLoc < qMarkLoc)) ||
846 qMarkLoc == 0)
847 {
848 KeywordToURI(aURIString, aPostData, aURI);
849 }
850 }
853 nsresult NS_NewURIFixup(nsIURIFixup **aURIFixup)
854 {
855 nsDefaultURIFixup *fixup = new nsDefaultURIFixup;
856 if (fixup == nullptr)
857 {
858 return NS_ERROR_OUT_OF_MEMORY;
859 }
860 return fixup->QueryInterface(NS_GET_IID(nsIURIFixup), (void **) aURIFixup);
861 }