/src/mozilla-central/docshell/base/nsDefaultURIFixup.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
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/. */ |
6 | | |
7 | | #include "nsNetCID.h" |
8 | | #include "nsNetUtil.h" |
9 | | #include "nsIProtocolHandler.h" |
10 | | |
11 | | #include "nsIFile.h" |
12 | | #include <algorithm> |
13 | | |
14 | | #ifdef MOZ_TOOLKIT_SEARCH |
15 | | #include "nsIBrowserSearchService.h" |
16 | | #endif |
17 | | |
18 | | #include "nsIURIFixup.h" |
19 | | #include "nsIURIMutator.h" |
20 | | #include "nsDefaultURIFixup.h" |
21 | | #include "mozilla/Preferences.h" |
22 | | #include "mozilla/dom/ContentChild.h" |
23 | | #include "mozilla/ipc/IPCStreamUtils.h" |
24 | | #include "mozilla/ipc/URIUtils.h" |
25 | | #include "mozilla/TextUtils.h" |
26 | | #include "mozilla/Tokenizer.h" |
27 | | #include "mozilla/Unused.h" |
28 | | #include "nsIObserverService.h" |
29 | | #include "nsXULAppAPI.h" |
30 | | |
31 | | // Used to check if external protocol schemes are usable |
32 | | #include "nsCExternalHandlerService.h" |
33 | | #include "nsIExternalProtocolService.h" |
34 | | |
35 | | using namespace mozilla; |
36 | | |
37 | | /* Implementation file */ |
38 | | NS_IMPL_ISUPPORTS(nsDefaultURIFixup, nsIURIFixup) |
39 | | |
40 | | static bool sInitializedPrefCaches = false; |
41 | | static bool sFixTypos = true; |
42 | | static bool sDNSFirstForSingleWords = false; |
43 | | static bool sFixupKeywords = true; |
44 | | |
45 | | nsDefaultURIFixup::nsDefaultURIFixup() |
46 | 0 | { |
47 | 0 | } |
48 | | |
49 | | nsDefaultURIFixup::~nsDefaultURIFixup() |
50 | 0 | { |
51 | 0 | } |
52 | | |
53 | | NS_IMETHODIMP |
54 | | nsDefaultURIFixup::CreateExposableURI(nsIURI* aURI, nsIURI** aReturn) |
55 | 0 | { |
56 | 0 | NS_ENSURE_ARG_POINTER(aURI); |
57 | 0 | NS_ENSURE_ARG_POINTER(aReturn); |
58 | 0 |
|
59 | 0 | bool isWyciwyg = false; |
60 | 0 | aURI->SchemeIs("wyciwyg", &isWyciwyg); |
61 | 0 |
|
62 | 0 | nsAutoCString userPass; |
63 | 0 | aURI->GetUserPass(userPass); |
64 | 0 |
|
65 | 0 | // most of the time we can just AddRef and return |
66 | 0 | if (!isWyciwyg && userPass.IsEmpty()) { |
67 | 0 | *aReturn = aURI; |
68 | 0 | NS_ADDREF(*aReturn); |
69 | 0 | return NS_OK; |
70 | 0 | } |
71 | 0 |
|
72 | 0 | // Rats, we have to massage the URI |
73 | 0 | nsCOMPtr<nsIURI> uri; |
74 | 0 | if (isWyciwyg) { |
75 | 0 | nsresult rv = nsContentUtils::RemoveWyciwygScheme(aURI, getter_AddRefs(uri)); |
76 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
77 | 0 | } else { |
78 | 0 | // No need to clone the URI as NS_MutateURI does that for us. |
79 | 0 | uri = aURI; |
80 | 0 | } |
81 | 0 |
|
82 | 0 | // hide user:pass unless overridden by pref |
83 | 0 | if (Preferences::GetBool("browser.fixup.hide_user_pass", true)) { |
84 | 0 | Unused << NS_MutateURI(uri) |
85 | 0 | .SetUserPass(EmptyCString()) |
86 | 0 | .Finalize(uri); |
87 | 0 | } |
88 | 0 |
|
89 | 0 | uri.forget(aReturn); |
90 | 0 | return NS_OK; |
91 | 0 | } |
92 | | |
93 | | NS_IMETHODIMP |
94 | | nsDefaultURIFixup::CreateFixupURI(const nsACString& aStringURI, |
95 | | uint32_t aFixupFlags, |
96 | | nsIInputStream** aPostData, nsIURI** aURI) |
97 | 0 | { |
98 | 0 | nsCOMPtr<nsIURIFixupInfo> fixupInfo; |
99 | 0 | nsresult rv = GetFixupURIInfo(aStringURI, aFixupFlags, aPostData, |
100 | 0 | getter_AddRefs(fixupInfo)); |
101 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
102 | 0 |
|
103 | 0 | fixupInfo->GetPreferredURI(aURI); |
104 | 0 | return rv; |
105 | 0 | } |
106 | | |
107 | | // Returns true if the URL contains a user:password@ or user@ |
108 | | static bool |
109 | | HasUserPassword(const nsACString& aStringURI) |
110 | 0 | { |
111 | 0 | mozilla::Tokenizer parser(aStringURI); |
112 | 0 | mozilla::Tokenizer::Token token; |
113 | 0 |
|
114 | 0 | // May start with any of "protocol:", "protocol://", "//", "://" |
115 | 0 | if (parser.Check(Tokenizer::TOKEN_WORD, token)) { // Skip protocol if any |
116 | 0 | } |
117 | 0 | if (parser.CheckChar(':')) { // Skip colon if found |
118 | 0 | } |
119 | 0 | while (parser.CheckChar('/')) { // Skip all of the following slashes |
120 | 0 | } |
121 | 0 |
|
122 | 0 | while (parser.Next(token)) { |
123 | 0 | if (token.Type() == Tokenizer::TOKEN_CHAR) { |
124 | 0 | if (token.AsChar() == '/') { |
125 | 0 | return false; |
126 | 0 | } |
127 | 0 | if (token.AsChar() == '@') { |
128 | 0 | return true; |
129 | 0 | } |
130 | 0 | } |
131 | 0 | } |
132 | 0 |
|
133 | 0 | return false; |
134 | 0 | } |
135 | | |
136 | | // Assume that 1 tab is accidental, but more than 1 implies this is |
137 | | // supposed to be tab-separated content. |
138 | | static bool |
139 | | MaybeTabSeparatedContent(const nsCString& aStringURI) |
140 | 0 | { |
141 | 0 | auto firstTab = aStringURI.FindChar('\t'); |
142 | 0 | return firstTab != kNotFound && aStringURI.RFindChar('\t') != firstTab; |
143 | 0 | } |
144 | | |
145 | | NS_IMETHODIMP |
146 | | nsDefaultURIFixup::GetFixupURIInfo(const nsACString& aStringURI, |
147 | | uint32_t aFixupFlags, |
148 | | nsIInputStream** aPostData, |
149 | | nsIURIFixupInfo** aInfo) |
150 | 0 | { |
151 | 0 | NS_ENSURE_ARG(!aStringURI.IsEmpty()); |
152 | 0 |
|
153 | 0 | nsresult rv; |
154 | 0 |
|
155 | 0 | nsAutoCString uriString(aStringURI); |
156 | 0 |
|
157 | 0 | // Eliminate embedded newlines, which single-line text fields now allow: |
158 | 0 | uriString.StripCRLF(); |
159 | 0 | // Cleanup the empty spaces and tabs that might be on each end: |
160 | 0 | uriString.Trim(" \t"); |
161 | 0 |
|
162 | 0 | NS_ENSURE_TRUE(!uriString.IsEmpty(), NS_ERROR_FAILURE); |
163 | 0 |
|
164 | 0 | RefPtr<nsDefaultURIFixupInfo> info = new nsDefaultURIFixupInfo(uriString); |
165 | 0 | NS_ADDREF(*aInfo = info); |
166 | 0 |
|
167 | 0 | nsCOMPtr<nsIIOService> ioService = |
168 | 0 | do_GetService(NS_IOSERVICE_CONTRACTID, &rv); |
169 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
170 | 0 | nsAutoCString scheme; |
171 | 0 | ioService->ExtractScheme(aStringURI, scheme); |
172 | 0 |
|
173 | 0 | // View-source is a pseudo scheme. We're interested in fixing up the stuff |
174 | 0 | // after it. The easiest way to do that is to call this method again with the |
175 | 0 | // "view-source:" lopped off and then prepend it again afterwards. |
176 | 0 |
|
177 | 0 | if (scheme.EqualsLiteral("view-source")) { |
178 | 0 | nsCOMPtr<nsIURIFixupInfo> uriInfo; |
179 | 0 | // We disable keyword lookup and alternate URIs so that small typos don't |
180 | 0 | // cause us to look at very different domains |
181 | 0 | uint32_t newFixupFlags = aFixupFlags & ~FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP |
182 | 0 | & ~FIXUP_FLAGS_MAKE_ALTERNATE_URI; |
183 | 0 |
|
184 | 0 | const uint32_t viewSourceLen = sizeof("view-source:") - 1; |
185 | 0 | nsAutoCString innerURIString(Substring(uriString, viewSourceLen, |
186 | 0 | uriString.Length() - |
187 | 0 | viewSourceLen)); |
188 | 0 | // Prevent recursion: |
189 | 0 | innerURIString.Trim(" "); |
190 | 0 | nsAutoCString innerScheme; |
191 | 0 | ioService->ExtractScheme(innerURIString, innerScheme); |
192 | 0 | if (innerScheme.EqualsLiteral("view-source")) { |
193 | 0 | return NS_ERROR_FAILURE; |
194 | 0 | } |
195 | 0 | |
196 | 0 | rv = GetFixupURIInfo(innerURIString, newFixupFlags, aPostData, |
197 | 0 | getter_AddRefs(uriInfo)); |
198 | 0 | if (NS_FAILED(rv)) { |
199 | 0 | return NS_ERROR_FAILURE; |
200 | 0 | } |
201 | 0 | nsAutoCString spec; |
202 | 0 | nsCOMPtr<nsIURI> uri; |
203 | 0 | uriInfo->GetPreferredURI(getter_AddRefs(uri)); |
204 | 0 | if (!uri) { |
205 | 0 | return NS_ERROR_FAILURE; |
206 | 0 | } |
207 | 0 | uri->GetSpec(spec); |
208 | 0 | uriString.AssignLiteral("view-source:"); |
209 | 0 | uriString.Append(spec); |
210 | 0 | } else { |
211 | 0 | // Check for if it is a file URL |
212 | 0 | nsCOMPtr<nsIURI> uri; |
213 | 0 | FileURIFixup(uriString, getter_AddRefs(uri)); |
214 | 0 | // NB: FileURIFixup only returns a URI if it had to fix the protocol to |
215 | 0 | // do so, so passing in file:///foo/bar will not hit this path: |
216 | 0 | if (uri) { |
217 | 0 | uri.swap(info->mFixedURI); |
218 | 0 | info->mPreferredURI = info->mFixedURI; |
219 | 0 | info->mFixupChangedProtocol = true; |
220 | 0 | return NS_OK; |
221 | 0 | } |
222 | 0 | } |
223 | 0 | |
224 | 0 | if (!sInitializedPrefCaches) { |
225 | 0 | // Check if we want to fix up common scheme typos. |
226 | 0 | rv = Preferences::AddBoolVarCache(&sFixTypos, |
227 | 0 | "browser.fixup.typo.scheme", |
228 | 0 | sFixTypos); |
229 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv), |
230 | 0 | "Failed to observe \"browser.fixup.typo.scheme\""); |
231 | 0 |
|
232 | 0 | rv = Preferences::AddBoolVarCache(&sDNSFirstForSingleWords, |
233 | 0 | "browser.fixup.dns_first_for_single_words", |
234 | 0 | sDNSFirstForSingleWords); |
235 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv), |
236 | 0 | "Failed to observe \"browser.fixup.dns_first_for_single_words\""); |
237 | 0 |
|
238 | 0 | rv = Preferences::AddBoolVarCache(&sFixupKeywords, "keyword.enabled", |
239 | 0 | sFixupKeywords); |
240 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed to observe \"keyword.enabled\""); |
241 | 0 | sInitializedPrefCaches = true; |
242 | 0 | } |
243 | 0 |
|
244 | 0 | // Fix up common scheme typos. |
245 | 0 | if (sFixTypos && (aFixupFlags & FIXUP_FLAG_FIX_SCHEME_TYPOS)) { |
246 | 0 | // Fast-path for common cases. |
247 | 0 | if (scheme.IsEmpty() || |
248 | 0 | scheme.EqualsLiteral("http") || |
249 | 0 | scheme.EqualsLiteral("https") || |
250 | 0 | scheme.EqualsLiteral("ftp") || |
251 | 0 | scheme.EqualsLiteral("file")) { |
252 | 0 | // Do nothing. |
253 | 0 | } else if (scheme.EqualsLiteral("ttp")) { |
254 | 0 | // ttp -> http. |
255 | 0 | uriString.ReplaceLiteral(0, 3, "http"); |
256 | 0 | scheme.AssignLiteral("http"); |
257 | 0 | info->mFixupChangedProtocol = true; |
258 | 0 | } else if (scheme.EqualsLiteral("htp")) { |
259 | 0 | // htp -> http. |
260 | 0 | uriString.ReplaceLiteral(0, 3, "http"); |
261 | 0 | scheme.AssignLiteral("http"); |
262 | 0 | info->mFixupChangedProtocol = true; |
263 | 0 | } else if (scheme.EqualsLiteral("ttps")) { |
264 | 0 | // ttps -> https. |
265 | 0 | uriString.ReplaceLiteral(0, 4, "https"); |
266 | 0 | scheme.AssignLiteral("https"); |
267 | 0 | info->mFixupChangedProtocol = true; |
268 | 0 | } else if (scheme.EqualsLiteral("tps")) { |
269 | 0 | // tps -> https. |
270 | 0 | uriString.ReplaceLiteral(0, 3, "https"); |
271 | 0 | scheme.AssignLiteral("https"); |
272 | 0 | info->mFixupChangedProtocol = true; |
273 | 0 | } else if (scheme.EqualsLiteral("ps")) { |
274 | 0 | // ps -> https. |
275 | 0 | uriString.ReplaceLiteral(0, 2, "https"); |
276 | 0 | scheme.AssignLiteral("https"); |
277 | 0 | info->mFixupChangedProtocol = true; |
278 | 0 | } else if (scheme.EqualsLiteral("htps")) { |
279 | 0 | // htps -> https. |
280 | 0 | uriString.ReplaceLiteral(0, 4, "https"); |
281 | 0 | scheme.AssignLiteral("https"); |
282 | 0 | info->mFixupChangedProtocol = true; |
283 | 0 | } else if (scheme.EqualsLiteral("ile")) { |
284 | 0 | // ile -> file. |
285 | 0 | uriString.ReplaceLiteral(0, 3, "file"); |
286 | 0 | scheme.AssignLiteral("file"); |
287 | 0 | info->mFixupChangedProtocol = true; |
288 | 0 | } else if (scheme.EqualsLiteral("le")) { |
289 | 0 | // le -> file. |
290 | 0 | uriString.ReplaceLiteral(0, 2, "file"); |
291 | 0 | scheme.AssignLiteral("file"); |
292 | 0 | info->mFixupChangedProtocol = true; |
293 | 0 | } |
294 | 0 | } |
295 | 0 |
|
296 | 0 | // Now we need to check whether "scheme" is something we don't |
297 | 0 | // really know about. |
298 | 0 | nsCOMPtr<nsIProtocolHandler> ourHandler, extHandler; |
299 | 0 |
|
300 | 0 | extHandler = do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "default"); |
301 | 0 | if (!scheme.IsEmpty()) { |
302 | 0 | ioService->GetProtocolHandler(scheme.get(), getter_AddRefs(ourHandler)); |
303 | 0 | } else { |
304 | 0 | ourHandler = extHandler; |
305 | 0 | } |
306 | 0 |
|
307 | 0 | if (ourHandler != extHandler || !PossiblyHostPortUrl(uriString)) { |
308 | 0 | // Just try to create an URL out of it |
309 | 0 | rv = NS_NewURI(getter_AddRefs(info->mFixedURI), uriString, nullptr); |
310 | 0 |
|
311 | 0 | if (!info->mFixedURI && rv != NS_ERROR_MALFORMED_URI) { |
312 | 0 | return rv; |
313 | 0 | } |
314 | 0 | } |
315 | 0 | |
316 | 0 | if (info->mFixedURI && ourHandler == extHandler && sFixupKeywords && |
317 | 0 | (aFixupFlags & FIXUP_FLAG_FIX_SCHEME_TYPOS)) { |
318 | 0 | nsCOMPtr<nsIExternalProtocolService> extProtService = |
319 | 0 | do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID); |
320 | 0 | if (extProtService) { |
321 | 0 | bool handlerExists = false; |
322 | 0 | rv = extProtService->ExternalProtocolHandlerExists(scheme.get(), |
323 | 0 | &handlerExists); |
324 | 0 | if (NS_FAILED(rv)) { |
325 | 0 | return rv; |
326 | 0 | } |
327 | 0 | // This basically means we're dealing with a theoretically valid |
328 | 0 | // URI... but we have no idea how to load it. (e.g. "christmas:humbug") |
329 | 0 | // It's more likely the user wants to search, and so we |
330 | 0 | // chuck this over to their preferred search provider instead: |
331 | 0 | if (!handlerExists) { |
332 | 0 | bool hasUserPassword = HasUserPassword(uriString); |
333 | 0 | if (!hasUserPassword) { |
334 | 0 | TryKeywordFixupForURIInfo(uriString, info, aPostData); |
335 | 0 | } else { |
336 | 0 | // If the given URL has a user:password we can't just pass it to the |
337 | 0 | // external protocol handler; we'll try using it with http instead later |
338 | 0 | info->mFixedURI = nullptr; |
339 | 0 | } |
340 | 0 | } |
341 | 0 | } |
342 | 0 | } |
343 | 0 |
|
344 | 0 | if (info->mFixedURI) { |
345 | 0 | if (!info->mPreferredURI) { |
346 | 0 | if (aFixupFlags & FIXUP_FLAGS_MAKE_ALTERNATE_URI) { |
347 | 0 | info->mFixupCreatedAlternateURI = MakeAlternateURI(info->mFixedURI); |
348 | 0 | } |
349 | 0 | info->mPreferredURI = info->mFixedURI; |
350 | 0 | } |
351 | 0 | return NS_OK; |
352 | 0 | } |
353 | 0 |
|
354 | 0 | // Fix up protocol string before calling KeywordURIFixup, because |
355 | 0 | // it cares about the hostname of such URIs: |
356 | 0 | nsCOMPtr<nsIURI> uriWithProtocol; |
357 | 0 | bool inputHadDuffProtocol = false; |
358 | 0 |
|
359 | 0 | // Prune duff protocol schemes |
360 | 0 | // |
361 | 0 | // ://totallybroken.url.com |
362 | 0 | // //shorthand.url.com |
363 | 0 | // |
364 | 0 | if (StringBeginsWith(uriString, NS_LITERAL_CSTRING("://"))) { |
365 | 0 | uriString = StringTail(uriString, uriString.Length() - 3); |
366 | 0 | inputHadDuffProtocol = true; |
367 | 0 | } else if (StringBeginsWith(uriString, NS_LITERAL_CSTRING("//"))) { |
368 | 0 | uriString = StringTail(uriString, uriString.Length() - 2); |
369 | 0 | inputHadDuffProtocol = true; |
370 | 0 | } |
371 | 0 |
|
372 | 0 | // Note: this rv gets returned at the end of this method if we don't fix up |
373 | 0 | // the protocol and don't do a keyword fixup after this (because the pref |
374 | 0 | // or the flags passed might not let us). |
375 | 0 | rv = NS_OK; |
376 | 0 | // Avoid fixing up content that looks like tab-separated values |
377 | 0 | if (!MaybeTabSeparatedContent(uriString)) { |
378 | 0 | rv = FixupURIProtocol(uriString, info, getter_AddRefs(uriWithProtocol)); |
379 | 0 | if (uriWithProtocol) { |
380 | 0 | info->mFixedURI = uriWithProtocol; |
381 | 0 | } |
382 | 0 | } |
383 | 0 |
|
384 | 0 | // See if it is a keyword |
385 | 0 | // Test whether keywords need to be fixed up |
386 | 0 | if (sFixupKeywords && (aFixupFlags & FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP) && |
387 | 0 | !inputHadDuffProtocol) { |
388 | 0 | if (NS_SUCCEEDED(KeywordURIFixup(uriString, info, aPostData)) && |
389 | 0 | info->mPreferredURI) { |
390 | 0 | return NS_OK; |
391 | 0 | } |
392 | 0 | } |
393 | 0 | |
394 | 0 | // Did the caller want us to try an alternative URI? |
395 | 0 | // If so, attempt to fixup http://foo into http://www.foo.com |
396 | 0 | |
397 | 0 | if (info->mFixedURI && aFixupFlags & FIXUP_FLAGS_MAKE_ALTERNATE_URI) { |
398 | 0 | info->mFixupCreatedAlternateURI = MakeAlternateURI(info->mFixedURI); |
399 | 0 | } |
400 | 0 |
|
401 | 0 | if (info->mFixedURI) { |
402 | 0 | info->mPreferredURI = info->mFixedURI; |
403 | 0 | return NS_OK; |
404 | 0 | } |
405 | 0 | |
406 | 0 | // If we still haven't been able to construct a valid URI, try to force a |
407 | 0 | // keyword match. This catches search strings with '.' or ':' in them. |
408 | 0 | if (sFixupKeywords && (aFixupFlags & FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP)) { |
409 | 0 | rv = TryKeywordFixupForURIInfo(aStringURI, info, aPostData); |
410 | 0 | } |
411 | 0 |
|
412 | 0 | return rv; |
413 | 0 | } |
414 | | |
415 | | NS_IMETHODIMP |
416 | | nsDefaultURIFixup::KeywordToURI(const nsACString& aKeyword, |
417 | | nsIInputStream** aPostData, |
418 | | nsIURIFixupInfo** aInfo) |
419 | 0 | { |
420 | 0 | RefPtr<nsDefaultURIFixupInfo> info = new nsDefaultURIFixupInfo(aKeyword); |
421 | 0 | NS_ADDREF(*aInfo = info); |
422 | 0 |
|
423 | 0 | if (aPostData) { |
424 | 0 | *aPostData = nullptr; |
425 | 0 | } |
426 | 0 | NS_ENSURE_STATE(Preferences::GetRootBranch()); |
427 | 0 |
|
428 | 0 | // Strip leading "?" and leading/trailing spaces from aKeyword |
429 | 0 | nsAutoCString keyword(aKeyword); |
430 | 0 | if (StringBeginsWith(keyword, NS_LITERAL_CSTRING("?"))) { |
431 | 0 | keyword.Cut(0, 1); |
432 | 0 | } |
433 | 0 | keyword.Trim(" "); |
434 | 0 |
|
435 | 0 | if (XRE_IsContentProcess()) { |
436 | 0 | dom::ContentChild* contentChild = dom::ContentChild::GetSingleton(); |
437 | 0 | if (!contentChild) { |
438 | 0 | return NS_ERROR_NOT_AVAILABLE; |
439 | 0 | } |
440 | 0 | |
441 | 0 | RefPtr<nsIInputStream> postData; |
442 | 0 | ipc::OptionalURIParams uri; |
443 | 0 | nsAutoString providerName; |
444 | 0 | if (!contentChild->SendKeywordToURI(keyword, &providerName, &postData, |
445 | 0 | &uri)) { |
446 | 0 | return NS_ERROR_FAILURE; |
447 | 0 | } |
448 | 0 | |
449 | 0 | CopyUTF8toUTF16(keyword, info->mKeywordAsSent); |
450 | 0 | info->mKeywordProviderName = providerName; |
451 | 0 |
|
452 | 0 | if (aPostData) { |
453 | 0 | postData.forget(aPostData); |
454 | 0 | } |
455 | 0 |
|
456 | 0 | nsCOMPtr<nsIURI> temp = DeserializeURI(uri); |
457 | 0 | info->mPreferredURI = temp.forget(); |
458 | 0 | return NS_OK; |
459 | 0 | } |
460 | 0 |
|
461 | 0 | #ifdef MOZ_TOOLKIT_SEARCH |
462 | 0 | // Try falling back to the search service's default search engine |
463 | 0 | nsCOMPtr<nsIBrowserSearchService> searchSvc = |
464 | 0 | do_GetService("@mozilla.org/browser/search-service;1"); |
465 | 0 | if (searchSvc) { |
466 | 0 | nsCOMPtr<nsISearchEngine> defaultEngine; |
467 | 0 | searchSvc->GetDefaultEngine(getter_AddRefs(defaultEngine)); |
468 | 0 | if (defaultEngine) { |
469 | 0 | nsCOMPtr<nsISearchSubmission> submission; |
470 | 0 | nsAutoString responseType; |
471 | 0 | // We allow default search plugins to specify alternate |
472 | 0 | // parameters that are specific to keyword searches. |
473 | 0 | NS_NAMED_LITERAL_STRING(mozKeywordSearch, |
474 | 0 | "application/x-moz-keywordsearch"); |
475 | 0 | bool supportsResponseType = false; |
476 | 0 | defaultEngine->SupportsResponseType(mozKeywordSearch, |
477 | 0 | &supportsResponseType); |
478 | 0 | if (supportsResponseType) { |
479 | 0 | responseType.Assign(mozKeywordSearch); |
480 | 0 | } |
481 | 0 |
|
482 | 0 | NS_ConvertUTF8toUTF16 keywordW(keyword); |
483 | 0 | defaultEngine->GetSubmission(keywordW, |
484 | 0 | responseType, |
485 | 0 | NS_LITERAL_STRING("keyword"), |
486 | 0 | getter_AddRefs(submission)); |
487 | 0 |
|
488 | 0 | if (submission) { |
489 | 0 | nsCOMPtr<nsIInputStream> postData; |
490 | 0 | submission->GetPostData(getter_AddRefs(postData)); |
491 | 0 | if (aPostData) { |
492 | 0 | postData.forget(aPostData); |
493 | 0 | } else if (postData) { |
494 | 0 | // The submission specifies POST data (i.e. the search |
495 | 0 | // engine's "method" is POST), but our caller didn't allow |
496 | 0 | // passing post data back. No point passing back a URL that |
497 | 0 | // won't load properly. |
498 | 0 | return NS_ERROR_FAILURE; |
499 | 0 | } |
500 | 0 | |
501 | 0 | defaultEngine->GetName(info->mKeywordProviderName); |
502 | 0 | info->mKeywordAsSent = keywordW; |
503 | 0 | return submission->GetUri(getter_AddRefs(info->mPreferredURI)); |
504 | 0 | } |
505 | 0 | } |
506 | 0 | } |
507 | 0 | #endif |
508 | 0 |
|
509 | 0 | // out of options |
510 | 0 | return NS_ERROR_NOT_AVAILABLE; |
511 | 0 | } |
512 | | |
513 | | // Helper to deal with passing around uri fixup stuff |
514 | | nsresult |
515 | | nsDefaultURIFixup::TryKeywordFixupForURIInfo(const nsACString& aURIString, |
516 | | nsDefaultURIFixupInfo* aFixupInfo, |
517 | | nsIInputStream** aPostData) |
518 | 0 | { |
519 | 0 | nsCOMPtr<nsIURIFixupInfo> keywordInfo; |
520 | 0 | nsresult rv = KeywordToURI(aURIString, aPostData, |
521 | 0 | getter_AddRefs(keywordInfo)); |
522 | 0 | if (NS_SUCCEEDED(rv)) { |
523 | 0 | keywordInfo->GetKeywordProviderName(aFixupInfo->mKeywordProviderName); |
524 | 0 | keywordInfo->GetKeywordAsSent(aFixupInfo->mKeywordAsSent); |
525 | 0 | keywordInfo->GetPreferredURI(getter_AddRefs(aFixupInfo->mPreferredURI)); |
526 | 0 | } |
527 | 0 | return rv; |
528 | 0 | } |
529 | | |
530 | | bool |
531 | | nsDefaultURIFixup::MakeAlternateURI(nsCOMPtr<nsIURI>& aURI) |
532 | 0 | { |
533 | 0 | if (!Preferences::GetRootBranch()) { |
534 | 0 | return false; |
535 | 0 | } |
536 | 0 | if (!Preferences::GetBool("browser.fixup.alternate.enabled", true)) { |
537 | 0 | return false; |
538 | 0 | } |
539 | 0 | |
540 | 0 | // Code only works for http. Not for any other protocol including https! |
541 | 0 | bool isHttp = false; |
542 | 0 | aURI->SchemeIs("http", &isHttp); |
543 | 0 | if (!isHttp) { |
544 | 0 | return false; |
545 | 0 | } |
546 | 0 | |
547 | 0 | // Security - URLs with user / password info should NOT be fixed up |
548 | 0 | nsAutoCString userpass; |
549 | 0 | aURI->GetUserPass(userpass); |
550 | 0 | if (!userpass.IsEmpty()) { |
551 | 0 | return false; |
552 | 0 | } |
553 | 0 | // Don't fix up hosts with ports |
554 | 0 | int32_t port; |
555 | 0 | aURI->GetPort(&port); |
556 | 0 | if (port != -1) { |
557 | 0 | return false; |
558 | 0 | } |
559 | 0 | |
560 | 0 | nsAutoCString oldHost; |
561 | 0 | aURI->GetHost(oldHost); |
562 | 0 |
|
563 | 0 | // Don't fix up 'localhost' because that's confusing: |
564 | 0 | if (oldHost.EqualsLiteral("localhost")) { |
565 | 0 | return false; |
566 | 0 | } |
567 | 0 | |
568 | 0 | nsAutoCString newHost; |
569 | 0 | // Count the dots |
570 | 0 | int32_t numDots = 0; |
571 | 0 | nsReadingIterator<char> iter; |
572 | 0 | nsReadingIterator<char> iterEnd; |
573 | 0 | oldHost.BeginReading(iter); |
574 | 0 | oldHost.EndReading(iterEnd); |
575 | 0 | while (iter != iterEnd) { |
576 | 0 | if (*iter == '.') { |
577 | 0 | numDots++; |
578 | 0 | } |
579 | 0 | ++iter; |
580 | 0 | } |
581 | 0 |
|
582 | 0 | // Get the prefix and suffix to stick onto the new hostname. By default these |
583 | 0 | // are www. & .com but they could be any other value, e.g. www. & .org |
584 | 0 |
|
585 | 0 | nsAutoCString prefix("www."); |
586 | 0 | nsAutoCString prefPrefix; |
587 | 0 | nsresult rv = |
588 | 0 | Preferences::GetCString("browser.fixup.alternate.prefix", prefPrefix); |
589 | 0 | if (NS_SUCCEEDED(rv)) { |
590 | 0 | prefix.Assign(prefPrefix); |
591 | 0 | } |
592 | 0 |
|
593 | 0 | nsAutoCString suffix(".com"); |
594 | 0 | nsAutoCString prefSuffix; |
595 | 0 | rv = Preferences::GetCString("browser.fixup.alternate.suffix", prefSuffix); |
596 | 0 | if (NS_SUCCEEDED(rv)) { |
597 | 0 | suffix.Assign(prefSuffix); |
598 | 0 | } |
599 | 0 |
|
600 | 0 | if (numDots == 0) { |
601 | 0 | newHost.Assign(prefix); |
602 | 0 | newHost.Append(oldHost); |
603 | 0 | newHost.Append(suffix); |
604 | 0 | } else if (numDots == 1) { |
605 | 0 | if (!prefix.IsEmpty() && |
606 | 0 | oldHost.EqualsIgnoreCase(prefix.get(), prefix.Length())) { |
607 | 0 | newHost.Assign(oldHost); |
608 | 0 | newHost.Append(suffix); |
609 | 0 | } else if (!suffix.IsEmpty()) { |
610 | 0 | newHost.Assign(prefix); |
611 | 0 | newHost.Append(oldHost); |
612 | 0 | } else { |
613 | 0 | // Do nothing |
614 | 0 | return false; |
615 | 0 | } |
616 | 0 | } else { |
617 | 0 | // Do nothing |
618 | 0 | return false; |
619 | 0 | } |
620 | 0 | |
621 | 0 | if (newHost.IsEmpty()) { |
622 | 0 | return false; |
623 | 0 | } |
624 | 0 | |
625 | 0 | // Assign the new host string over the old one |
626 | 0 | Unused << NS_MutateURI(aURI) |
627 | 0 | .SetHost(newHost) |
628 | 0 | .Finalize(aURI); |
629 | 0 |
|
630 | 0 | return true; |
631 | 0 | } |
632 | | |
633 | | nsresult |
634 | | nsDefaultURIFixup::FileURIFixup(const nsACString& aStringURI, nsIURI** aURI) |
635 | 0 | { |
636 | 0 | nsAutoCString uriSpecOut; |
637 | 0 |
|
638 | 0 | nsresult rv = ConvertFileToStringURI(aStringURI, uriSpecOut); |
639 | 0 | if (NS_SUCCEEDED(rv)) { |
640 | 0 | // if this is file url, uriSpecOut is already in FS charset |
641 | 0 | if (NS_SUCCEEDED(NS_NewURI(aURI, uriSpecOut.get(), nullptr))) { |
642 | 0 | return NS_OK; |
643 | 0 | } |
644 | 0 | } |
645 | 0 | return NS_ERROR_FAILURE; |
646 | 0 | } |
647 | | |
648 | | nsresult |
649 | | nsDefaultURIFixup::ConvertFileToStringURI(const nsACString& aIn, |
650 | | nsCString& aResult) |
651 | 0 | { |
652 | 0 | bool attemptFixup = false; |
653 | 0 |
|
654 | | #if defined(XP_WIN) |
655 | | // Check for \ in the url-string or just a drive (PC) |
656 | | if (aIn.Contains('\\') || |
657 | | (aIn.Length() == 2 && (aIn.Last() == ':' || aIn.Last() == '|'))) { |
658 | | attemptFixup = true; |
659 | | } |
660 | | #elif defined(XP_UNIX) |
661 | | // Check if it starts with / (UNIX) |
662 | 0 | if (aIn.First() == '/') { |
663 | 0 | attemptFixup = true; |
664 | 0 | } |
665 | | #else |
666 | | // Do nothing (All others for now) |
667 | | #endif |
668 | |
|
669 | 0 | if (attemptFixup) { |
670 | 0 | // Test if this is a valid path by trying to create a local file |
671 | 0 | // object. The URL of that is returned if successful. |
672 | 0 |
|
673 | 0 | nsCOMPtr<nsIFile> filePath; |
674 | 0 | nsresult rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(aIn), false, |
675 | 0 | getter_AddRefs(filePath)); |
676 | 0 |
|
677 | 0 | if (NS_SUCCEEDED(rv)) { |
678 | 0 | NS_GetURLSpecFromFile(filePath, aResult); |
679 | 0 | return NS_OK; |
680 | 0 | } |
681 | 0 | } |
682 | 0 | |
683 | 0 | return NS_ERROR_FAILURE; |
684 | 0 | } |
685 | | |
686 | | nsresult |
687 | | nsDefaultURIFixup::FixupURIProtocol(const nsACString& aURIString, |
688 | | nsDefaultURIFixupInfo* aFixupInfo, |
689 | | nsIURI** aURI) |
690 | 0 | { |
691 | 0 | nsAutoCString uriString(aURIString); |
692 | 0 | *aURI = nullptr; |
693 | 0 |
|
694 | 0 | // Add ftp:// or http:// to front of url if it has no spec |
695 | 0 | // |
696 | 0 | // Should fix: |
697 | 0 | // |
698 | 0 | // no-scheme.com |
699 | 0 | // ftp.no-scheme.com |
700 | 0 | // ftp4.no-scheme.com |
701 | 0 | // no-scheme.com/query?foo=http://www.foo.com |
702 | 0 | // user:pass@no-scheme.com |
703 | 0 | // |
704 | 0 | int32_t schemeDelim = uriString.Find("://"); |
705 | 0 | int32_t firstDelim = uriString.FindCharInSet("/:"); |
706 | 0 | if (schemeDelim <= 0 || |
707 | 0 | (firstDelim != -1 && schemeDelim > firstDelim)) { |
708 | 0 | // find host name |
709 | 0 | int32_t hostPos = uriString.FindCharInSet("/:?#"); |
710 | 0 | if (hostPos == -1) { |
711 | 0 | hostPos = uriString.Length(); |
712 | 0 | } |
713 | 0 |
|
714 | 0 | // extract host name |
715 | 0 | nsAutoCString hostSpec; |
716 | 0 | uriString.Left(hostSpec, hostPos); |
717 | 0 |
|
718 | 0 | // insert url spec corresponding to host name |
719 | 0 | uriString.InsertLiteral("http://", 0); |
720 | 0 | aFixupInfo->mFixupChangedProtocol = true; |
721 | 0 | } // end if checkprotocol |
722 | 0 |
|
723 | 0 | return NS_NewURI(aURI, uriString, nullptr); |
724 | 0 | } |
725 | | |
726 | | bool |
727 | | nsDefaultURIFixup::PossiblyHostPortUrl(const nsACString& aUrl) |
728 | 0 | { |
729 | 0 | // Oh dear, the protocol is invalid. Test if the protocol might |
730 | 0 | // actually be a url without a protocol: |
731 | 0 | // |
732 | 0 | // http://www.faqs.org/rfcs/rfc1738.html |
733 | 0 | // http://www.faqs.org/rfcs/rfc2396.html |
734 | 0 | // |
735 | 0 | // e.g. Anything of the form: |
736 | 0 | // |
737 | 0 | // <hostname>:<port> or |
738 | 0 | // <hostname>:<port>/ |
739 | 0 | // |
740 | 0 | // Where <hostname> is a string of alphanumeric characters and dashes |
741 | 0 | // separated by dots. |
742 | 0 | // and <port> is a 5 or less digits. This actually breaks the rfc2396 |
743 | 0 | // definition of a scheme which allows dots in schemes. |
744 | 0 | // |
745 | 0 | // Note: |
746 | 0 | // People expecting this to work with |
747 | 0 | // <user>:<password>@<host>:<port>/<url-path> will be disappointed! |
748 | 0 | // |
749 | 0 | // Note: Parser could be a lot tighter, tossing out silly hostnames |
750 | 0 | // such as those containing consecutive dots and so on. |
751 | 0 |
|
752 | 0 | // Read the hostname which should of the form |
753 | 0 | // [a-zA-Z0-9\-]+(\.[a-zA-Z0-9\-]+)*: |
754 | 0 |
|
755 | 0 | nsACString::const_iterator iterBegin; |
756 | 0 | nsACString::const_iterator iterEnd; |
757 | 0 | aUrl.BeginReading(iterBegin); |
758 | 0 | aUrl.EndReading(iterEnd); |
759 | 0 | nsACString::const_iterator iter = iterBegin; |
760 | 0 |
|
761 | 0 | while (iter != iterEnd) { |
762 | 0 | uint32_t chunkSize = 0; |
763 | 0 | // Parse a chunk of the address |
764 | 0 | while (iter != iterEnd && |
765 | 0 | (*iter == '-' || |
766 | 0 | IsAsciiAlpha(*iter) || |
767 | 0 | IsAsciiDigit(*iter))) { |
768 | 0 | ++chunkSize; |
769 | 0 | ++iter; |
770 | 0 | } |
771 | 0 | if (chunkSize == 0 || iter == iterEnd) { |
772 | 0 | return false; |
773 | 0 | } |
774 | 0 | if (*iter == ':') { |
775 | 0 | // Go onto checking the for the digits |
776 | 0 | break; |
777 | 0 | } |
778 | 0 | if (*iter != '.') { |
779 | 0 | // Whatever it is, it ain't a hostname! |
780 | 0 | return false; |
781 | 0 | } |
782 | 0 | ++iter; |
783 | 0 | } |
784 | 0 | if (iter == iterEnd) { |
785 | 0 | // No point continuing since there is no colon |
786 | 0 | return false; |
787 | 0 | } |
788 | 0 | ++iter; |
789 | 0 |
|
790 | 0 | // Count the number of digits after the colon and before the |
791 | 0 | // next forward slash (or end of string) |
792 | 0 |
|
793 | 0 | uint32_t digitCount = 0; |
794 | 0 | while (iter != iterEnd && digitCount <= 5) { |
795 | 0 | if (IsAsciiDigit(*iter)) { |
796 | 0 | digitCount++; |
797 | 0 | } else if (*iter == '/') { |
798 | 0 | break; |
799 | 0 | } else { |
800 | 0 | // Whatever it is, it ain't a port! |
801 | 0 | return false; |
802 | 0 | } |
803 | 0 | ++iter; |
804 | 0 | } |
805 | 0 | if (digitCount == 0 || digitCount > 5) { |
806 | 0 | // No digits or more digits than a port would have. |
807 | 0 | return false; |
808 | 0 | } |
809 | 0 | |
810 | 0 | // Yes, it's possibly a host:port url |
811 | 0 | return true; |
812 | 0 | } |
813 | | |
814 | | nsresult |
815 | | nsDefaultURIFixup::KeywordURIFixup(const nsACString& aURIString, |
816 | | nsDefaultURIFixupInfo* aFixupInfo, |
817 | | nsIInputStream** aPostData) |
818 | 0 | { |
819 | 0 | // These are keyword formatted strings |
820 | 0 | // "what is mozilla" |
821 | 0 | // "what is mozilla?" |
822 | 0 | // "docshell site:mozilla.org" - has no dot/colon in the first space-separated substring |
823 | 0 | // "?mozilla" - anything that begins with a question mark |
824 | 0 | // "?site:mozilla.org docshell" |
825 | 0 | // Things that have a quote before the first dot/colon |
826 | 0 | // "mozilla" - checked against a whitelist to see if it's a host or not |
827 | 0 | // ".mozilla", "mozilla." - ditto |
828 | 0 |
|
829 | 0 | // These are not keyword formatted strings |
830 | 0 | // "www.blah.com" - first space-separated substring contains a dot, doesn't start with "?" |
831 | 0 | // "www.blah.com stuff" |
832 | 0 | // "nonQualifiedHost:80" - first space-separated substring contains a colon, doesn't start with "?" |
833 | 0 | // "nonQualifiedHost:80 args" |
834 | 0 | // "nonQualifiedHost?" |
835 | 0 | // "nonQualifiedHost?args" |
836 | 0 | // "nonQualifiedHost?some args" |
837 | 0 | // "blah.com." |
838 | 0 |
|
839 | 0 | // Note: uint32_t(kNotFound) is greater than any actual location |
840 | 0 | // in practice. So if we cast all locations to uint32_t, then a < |
841 | 0 | // b guarantees that either b is kNotFound and a is found, or both |
842 | 0 | // are found and a found before b. |
843 | 0 |
|
844 | 0 | uint32_t firstDotLoc = uint32_t(kNotFound); |
845 | 0 | uint32_t lastDotLoc = uint32_t(kNotFound); |
846 | 0 | uint32_t firstColonLoc = uint32_t(kNotFound); |
847 | 0 | uint32_t firstQuoteLoc = uint32_t(kNotFound); |
848 | 0 | uint32_t firstSpaceLoc = uint32_t(kNotFound); |
849 | 0 | uint32_t firstQMarkLoc = uint32_t(kNotFound); |
850 | 0 | uint32_t lastLSBracketLoc = uint32_t(kNotFound); |
851 | 0 | uint32_t lastSlashLoc = uint32_t(kNotFound); |
852 | 0 | uint32_t pos = 0; |
853 | 0 | uint32_t foundDots = 0; |
854 | 0 | uint32_t foundColons = 0; |
855 | 0 | uint32_t foundDigits = 0; |
856 | 0 | uint32_t foundRSBrackets = 0; |
857 | 0 | bool looksLikeIpv6 = true; |
858 | 0 | bool hasAsciiAlpha = false; |
859 | 0 |
|
860 | 0 | nsACString::const_iterator iterBegin; |
861 | 0 | nsACString::const_iterator iterEnd; |
862 | 0 | aURIString.BeginReading(iterBegin); |
863 | 0 | aURIString.EndReading(iterEnd); |
864 | 0 | nsACString::const_iterator iter = iterBegin; |
865 | 0 |
|
866 | 0 | while (iter != iterEnd) { |
867 | 0 | if (pos >= 1 && foundRSBrackets == 0) { |
868 | 0 | if (!(lastLSBracketLoc == 0 && |
869 | 0 | (*iter == ':' || |
870 | 0 | *iter == '.' || |
871 | 0 | *iter == ']' || |
872 | 0 | (*iter >= 'a' && *iter <= 'f') || |
873 | 0 | (*iter >= 'A' && *iter <= 'F') || |
874 | 0 | IsAsciiDigit(*iter)))) { |
875 | 0 | looksLikeIpv6 = false; |
876 | 0 | } |
877 | 0 | } |
878 | 0 |
|
879 | 0 | // If we're at the end of the string or this is the first slash, |
880 | 0 | // check if the thing before the slash looks like ipv4: |
881 | 0 | if ((iterEnd - iter == 1 || |
882 | 0 | (lastSlashLoc == uint32_t(kNotFound) && *iter == '/')) && |
883 | 0 | // Need 2 or 3 dots + only digits |
884 | 0 | (foundDots == 2 || foundDots == 3) && |
885 | 0 | // and they should be all that came before now: |
886 | 0 | (foundDots + foundDigits == pos || |
887 | 0 | // or maybe there was also exactly 1 colon that came after the last dot, |
888 | 0 | // and the digits, dots and colon were all that came before now: |
889 | 0 | (foundColons == 1 && firstColonLoc > lastDotLoc && |
890 | 0 | foundDots + foundDigits + foundColons == pos))) { |
891 | 0 | // Hurray, we got ourselves some ipv4! |
892 | 0 | // At this point, there's no way we will do a keyword lookup, so just bail immediately: |
893 | 0 | return NS_OK; |
894 | 0 | } |
895 | 0 | |
896 | 0 | if (*iter == '.') { |
897 | 0 | ++foundDots; |
898 | 0 | lastDotLoc = pos; |
899 | 0 | if (firstDotLoc == uint32_t(kNotFound)) { |
900 | 0 | firstDotLoc = pos; |
901 | 0 | } |
902 | 0 | } else if (*iter == ':') { |
903 | 0 | ++foundColons; |
904 | 0 | if (firstColonLoc == uint32_t(kNotFound)) { |
905 | 0 | firstColonLoc = pos; |
906 | 0 | } |
907 | 0 | } else if (*iter == ' ' && firstSpaceLoc == uint32_t(kNotFound)) { |
908 | 0 | firstSpaceLoc = pos; |
909 | 0 | } else if (*iter == '?' && firstQMarkLoc == uint32_t(kNotFound)) { |
910 | 0 | firstQMarkLoc = pos; |
911 | 0 | } else if ((*iter == '\'' || *iter == '"') && |
912 | 0 | firstQuoteLoc == uint32_t(kNotFound)) { |
913 | 0 | firstQuoteLoc = pos; |
914 | 0 | } else if (*iter == '[') { |
915 | 0 | lastLSBracketLoc = pos; |
916 | 0 | } else if (*iter == ']') { |
917 | 0 | foundRSBrackets++; |
918 | 0 | } else if (*iter == '/') { |
919 | 0 | lastSlashLoc = pos; |
920 | 0 | } else if (IsAsciiAlpha(*iter)) { |
921 | 0 | hasAsciiAlpha = true; |
922 | 0 | } else if (IsAsciiDigit(*iter)) { |
923 | 0 | ++foundDigits; |
924 | 0 | } |
925 | 0 |
|
926 | 0 | pos++; |
927 | 0 | iter++; |
928 | 0 | } |
929 | 0 |
|
930 | 0 | if (lastLSBracketLoc > 0 || foundRSBrackets != 1) { |
931 | 0 | looksLikeIpv6 = false; |
932 | 0 | } |
933 | 0 |
|
934 | 0 | // If there are only colons and only hexadecimal characters ([a-z][0-9]) |
935 | 0 | // enclosed in [], then don't do a keyword lookup |
936 | 0 | if (looksLikeIpv6) { |
937 | 0 | return NS_OK; |
938 | 0 | } |
939 | 0 | |
940 | 0 | nsAutoCString asciiHost; |
941 | 0 | nsAutoCString displayHost; |
942 | 0 |
|
943 | 0 | bool isValidHost = |
944 | 0 | aFixupInfo->mFixedURI && |
945 | 0 | NS_SUCCEEDED(aFixupInfo->mFixedURI->GetAsciiHost(asciiHost)) && |
946 | 0 | !asciiHost.IsEmpty(); |
947 | 0 |
|
948 | 0 | bool isValidDisplayHost = |
949 | 0 | aFixupInfo->mFixedURI && |
950 | 0 | NS_SUCCEEDED(aFixupInfo->mFixedURI->GetDisplayHost(displayHost)) && |
951 | 0 | !displayHost.IsEmpty(); |
952 | 0 |
|
953 | 0 | nsresult rv = NS_OK; |
954 | 0 | // We do keyword lookups if a space or quote preceded the dot, colon |
955 | 0 | // or question mark (or if the latter is not found, or if the input starts |
956 | 0 | // with a question mark) |
957 | 0 | if (((firstSpaceLoc < firstDotLoc || firstQuoteLoc < firstDotLoc) && |
958 | 0 | (firstSpaceLoc < firstColonLoc || firstQuoteLoc < firstColonLoc) && |
959 | 0 | (firstSpaceLoc < firstQMarkLoc || firstQuoteLoc < firstQMarkLoc)) || |
960 | 0 | firstQMarkLoc == 0) { |
961 | 0 | rv = TryKeywordFixupForURIInfo(aFixupInfo->mOriginalInput, aFixupInfo, |
962 | 0 | aPostData); |
963 | 0 | // ... or when the asciiHost is the same as displayHost and there are no |
964 | 0 | // characters from [a-z][A-Z] |
965 | 0 | } else if (isValidHost && isValidDisplayHost && !hasAsciiAlpha && |
966 | 0 | asciiHost.EqualsIgnoreCase(displayHost.get())) { |
967 | 0 | if (!sDNSFirstForSingleWords) { |
968 | 0 | rv = TryKeywordFixupForURIInfo(aFixupInfo->mOriginalInput, aFixupInfo, |
969 | 0 | aPostData); |
970 | 0 | } |
971 | 0 | } |
972 | 0 | // ... or if there is no question mark or colon, and there is either no |
973 | 0 | // dot, or exactly 1 and it is the first or last character of the input: |
974 | 0 | else if ((firstDotLoc == uint32_t(kNotFound) || |
975 | 0 | (foundDots == 1 && (firstDotLoc == 0 || |
976 | 0 | firstDotLoc == aURIString.Length() - 1))) && |
977 | 0 | firstColonLoc == uint32_t(kNotFound) && |
978 | 0 | firstQMarkLoc == uint32_t(kNotFound)) { |
979 | 0 | if (isValidHost && IsDomainWhitelisted(asciiHost, firstDotLoc)) { |
980 | 0 | return NS_OK; |
981 | 0 | } |
982 | 0 | |
983 | 0 | // ... unless there are no dots, and a slash, and alpha characters, and |
984 | 0 | // this is a valid host: |
985 | 0 | if (firstDotLoc == uint32_t(kNotFound) && |
986 | 0 | lastSlashLoc != uint32_t(kNotFound) && |
987 | 0 | hasAsciiAlpha && isValidHost) { |
988 | 0 | return NS_OK; |
989 | 0 | } |
990 | 0 | |
991 | 0 | // If we get here, we don't have a valid URI, or we did but the |
992 | 0 | // host is not whitelisted, so we do a keyword search *anyway*: |
993 | 0 | rv = TryKeywordFixupForURIInfo(aFixupInfo->mOriginalInput, aFixupInfo, |
994 | 0 | aPostData); |
995 | 0 | } |
996 | 0 | return rv; |
997 | 0 | } |
998 | | |
999 | | bool |
1000 | | nsDefaultURIFixup::IsDomainWhitelisted(const nsACString& aAsciiHost, |
1001 | | const uint32_t aDotLoc) |
1002 | 0 | { |
1003 | 0 | if (sDNSFirstForSingleWords) { |
1004 | 0 | return true; |
1005 | 0 | } |
1006 | 0 | // Check if this domain is whitelisted as an actual |
1007 | 0 | // domain (which will prevent a keyword query) |
1008 | 0 | // NB: any processing of the host here should stay in sync with |
1009 | 0 | // code in the front-end(s) that set the pref. |
1010 | 0 | |
1011 | 0 | nsAutoCString pref("browser.fixup.domainwhitelist."); |
1012 | 0 |
|
1013 | 0 | if (aDotLoc == aAsciiHost.Length() - 1) { |
1014 | 0 | pref.Append(Substring(aAsciiHost, 0, aAsciiHost.Length() - 1)); |
1015 | 0 | } else { |
1016 | 0 | pref.Append(aAsciiHost); |
1017 | 0 | } |
1018 | 0 |
|
1019 | 0 | return Preferences::GetBool(pref.get(), false); |
1020 | 0 | } |
1021 | | |
1022 | | NS_IMETHODIMP |
1023 | | nsDefaultURIFixup::IsDomainWhitelisted(const nsACString& aDomain, |
1024 | | const uint32_t aDotLoc, |
1025 | | bool* aResult) |
1026 | 0 | { |
1027 | 0 | *aResult = IsDomainWhitelisted(aDomain, aDotLoc); |
1028 | 0 | return NS_OK; |
1029 | 0 | } |
1030 | | |
1031 | | /* Implementation of nsIURIFixupInfo */ |
1032 | | NS_IMPL_ISUPPORTS(nsDefaultURIFixupInfo, nsIURIFixupInfo) |
1033 | | |
1034 | | nsDefaultURIFixupInfo::nsDefaultURIFixupInfo(const nsACString& aOriginalInput) |
1035 | | : mFixupChangedProtocol(false) |
1036 | | , mFixupCreatedAlternateURI(false) |
1037 | 0 | { |
1038 | 0 | mOriginalInput = aOriginalInput; |
1039 | 0 | } |
1040 | | |
1041 | | nsDefaultURIFixupInfo::~nsDefaultURIFixupInfo() |
1042 | 0 | { |
1043 | 0 | } |
1044 | | |
1045 | | NS_IMETHODIMP |
1046 | | nsDefaultURIFixupInfo::GetConsumer(nsISupports** aConsumer) |
1047 | 0 | { |
1048 | 0 | *aConsumer = mConsumer; |
1049 | 0 | NS_IF_ADDREF(*aConsumer); |
1050 | 0 | return NS_OK; |
1051 | 0 | } |
1052 | | |
1053 | | NS_IMETHODIMP |
1054 | | nsDefaultURIFixupInfo::SetConsumer(nsISupports* aConsumer) |
1055 | 0 | { |
1056 | 0 | mConsumer = aConsumer; |
1057 | 0 | return NS_OK; |
1058 | 0 | } |
1059 | | |
1060 | | NS_IMETHODIMP |
1061 | | nsDefaultURIFixupInfo::GetPreferredURI(nsIURI** aPreferredURI) |
1062 | 0 | { |
1063 | 0 | *aPreferredURI = mPreferredURI; |
1064 | 0 | NS_IF_ADDREF(*aPreferredURI); |
1065 | 0 | return NS_OK; |
1066 | 0 | } |
1067 | | |
1068 | | NS_IMETHODIMP |
1069 | | nsDefaultURIFixupInfo::GetFixedURI(nsIURI** aFixedURI) |
1070 | 0 | { |
1071 | 0 | *aFixedURI = mFixedURI; |
1072 | 0 | NS_IF_ADDREF(*aFixedURI); |
1073 | 0 | return NS_OK; |
1074 | 0 | } |
1075 | | |
1076 | | NS_IMETHODIMP |
1077 | | nsDefaultURIFixupInfo::GetKeywordProviderName(nsAString& aResult) |
1078 | 0 | { |
1079 | 0 | aResult = mKeywordProviderName; |
1080 | 0 | return NS_OK; |
1081 | 0 | } |
1082 | | |
1083 | | NS_IMETHODIMP |
1084 | | nsDefaultURIFixupInfo::GetKeywordAsSent(nsAString& aResult) |
1085 | 0 | { |
1086 | 0 | aResult = mKeywordAsSent; |
1087 | 0 | return NS_OK; |
1088 | 0 | } |
1089 | | |
1090 | | NS_IMETHODIMP |
1091 | | nsDefaultURIFixupInfo::GetFixupChangedProtocol(bool* aResult) |
1092 | 0 | { |
1093 | 0 | *aResult = mFixupChangedProtocol; |
1094 | 0 | return NS_OK; |
1095 | 0 | } |
1096 | | |
1097 | | NS_IMETHODIMP |
1098 | | nsDefaultURIFixupInfo::GetFixupCreatedAlternateURI(bool* aResult) |
1099 | 0 | { |
1100 | 0 | *aResult = mFixupCreatedAlternateURI; |
1101 | 0 | return NS_OK; |
1102 | 0 | } |
1103 | | |
1104 | | NS_IMETHODIMP |
1105 | | nsDefaultURIFixupInfo::GetOriginalInput(nsACString& aResult) |
1106 | 0 | { |
1107 | 0 | aResult = mOriginalInput; |
1108 | 0 | return NS_OK; |
1109 | 0 | } |