OLD | NEW |
(Empty) | |
| 1 /* This Source Code Form is subject to the terms of the Mozilla Public |
| 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
| 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| 4 |
| 5 Cu.import("resource://gre/modules/Services.jsm"); |
| 6 Cu.import("resource://gre/modules/XPCOMUtils.jsm"); |
| 7 |
| 8 let {Prefs} = require("prefs"); |
| 9 let {WindowObserver} = require("windowObserver"); |
| 10 let {getSchemeCorrection, isKnownScheme, getDomainCorrection, getDomainReferral,
onWhitelistEntryAdded} = require("typoRules"); |
| 11 let {processTypedDomain, processDomainCorrection, processFalsePositive} = requir
e("typoCollector"); |
| 12 let appIntegration = require("typoAppIntegration"); |
| 13 let netError = require("typoNetError"); |
| 14 |
| 15 // Attach our handlers to all browser windows |
| 16 new WindowObserver( |
| 17 { |
| 18 applyToWindow: function(window) |
| 19 { |
| 20 if (!appIntegration.isKnownWindow(window)) |
| 21 return; |
| 22 |
| 23 netError.applyToWindow(window); |
| 24 appIntegration.applyToWindow(window, correctURL); |
| 25 }, |
| 26 |
| 27 removeFromWindow: function(window) |
| 28 { |
| 29 if (!appIntegration.isKnownWindow(window)) |
| 30 return; |
| 31 |
| 32 netError.removeFromWindow(window); |
| 33 appIntegration.removeFromWindow(window); |
| 34 } |
| 35 }); |
| 36 |
| 37 function parseURL(url) |
| 38 { |
| 39 if (/^\s*((?:\w+:)?\/*(?:[^\/#]*@)?)([^\/:#]*)/.test(url)) |
| 40 return [RegExp.$1, RegExp.$2.toLowerCase(), RegExp.rightContext]; |
| 41 else |
| 42 return [url, null, null]; |
| 43 } |
| 44 |
| 45 function isIPAddress(domain) |
| 46 { |
| 47 try |
| 48 { |
| 49 Services.eTLD.getBaseDomainFromHost(domain); |
| 50 return false; |
| 51 } |
| 52 catch (e) |
| 53 { |
| 54 return (e.result == Cr.NS_ERROR_HOST_IS_IP_ADDRESS); |
| 55 } |
| 56 } |
| 57 |
| 58 function correctURL(window, value) |
| 59 { |
| 60 let hasCorrection = false; |
| 61 |
| 62 value = value.trim(); |
| 63 if (value.length == 0) |
| 64 return null; |
| 65 |
| 66 // Replace backslashes |
| 67 value = value.replace(/\\/g, "/"); |
| 68 |
| 69 // Does the URL scheme need correcting? |
| 70 if (/^([^\/]+)(\/.*)/.test(value)) |
| 71 { |
| 72 let scheme = RegExp.$1; |
| 73 let suffix = RegExp.$2; |
| 74 let correction = getSchemeCorrection(scheme) |
| 75 if (correction != scheme) |
| 76 { |
| 77 value = correction + suffix; |
| 78 hasCorrection = true; |
| 79 } |
| 80 } |
| 81 |
| 82 // Ignore URL schemes that we don't know |
| 83 if (/^([\w\-]+:)/.test(value) && !isKnownScheme(RegExp.$1)) |
| 84 return null; |
| 85 |
| 86 // Ignore search keywords and such |
| 87 if ("getShortcutOrURI" in window && window.getShortcutOrURI(value) != value) |
| 88 return null; |
| 89 |
| 90 // Spaces before the first slash or period is probably a quick search |
| 91 if (/^[^\/\.\s]+\s/.test(value)) |
| 92 return null; |
| 93 |
| 94 let [prefix, domain, suffix] = parseURL(value); |
| 95 if (!domain) |
| 96 return null; |
| 97 |
| 98 let oldDomain = domain; |
| 99 if (!isIPAddress(domain)) |
| 100 { |
| 101 processTypedDomain(domain); |
| 102 |
| 103 let newDomain = getDomainCorrection(domain); |
| 104 if (newDomain != domain) |
| 105 { |
| 106 processDomainCorrection(domain, newDomain); |
| 107 domain = newDomain; |
| 108 hasCorrection = true; |
| 109 |
| 110 let referral = getDomainReferral(domain.replace(/^www\./, "")); |
| 111 if (referral) |
| 112 { |
| 113 // We need to add a query string parameter when sending users to this do
main |
| 114 let anchorIndex = suffix.indexOf("#"); |
| 115 let anchor = ""; |
| 116 if (anchorIndex >= 0) |
| 117 { |
| 118 anchor = suffix.substr(anchorIndex); |
| 119 suffix = suffix.substr(0, anchorIndex); |
| 120 } |
| 121 |
| 122 let queryIndex = suffix.indexOf("?"); |
| 123 if (queryIndex >= 0) |
| 124 { |
| 125 if (!/&$/.test(suffix)) |
| 126 suffix += "&"; |
| 127 suffix += referral; |
| 128 } |
| 129 else |
| 130 { |
| 131 if (suffix.indexOf("/") < 0) |
| 132 suffix += "/"; |
| 133 suffix += "?" + referral; |
| 134 } |
| 135 |
| 136 suffix += anchor; |
| 137 } |
| 138 } |
| 139 } |
| 140 |
| 141 if (!hasCorrection) |
| 142 return null; |
| 143 |
| 144 if (!appIntegration.isTypoCorrectionEnabled(window, prefix, domain, suffix)) |
| 145 return; |
| 146 |
| 147 // Show infobar to inform and ask about correction |
| 148 let [message, yes, no] = getInfobarTexts(); |
| 149 message = message.replace(/\?1\?/g, prefix+domain); |
| 150 let buttons = [ |
| 151 { |
| 152 label: yes, |
| 153 accessKey: null, |
| 154 callback: function() |
| 155 { |
| 156 // Yes: Do nothing |
| 157 } |
| 158 }, |
| 159 { |
| 160 label: no, |
| 161 accessKey: null, |
| 162 callback: function() |
| 163 { |
| 164 // No: Add to list of corrections (ignore) |
| 165 let entry = oldDomain.replace(/^www\./, ""); |
| 166 Prefs.whitelist[entry] = true; |
| 167 onWhitelistEntryAdded(entry); |
| 168 Prefs.whitelist = JSON.parse(JSON.stringify(Prefs.whitelist)); |
| 169 |
| 170 appIntegration.loadURI(window, value); |
| 171 processFalsePositive(domain, oldDomain); |
| 172 } |
| 173 } |
| 174 ]; |
| 175 // We need to have persistence being set to 1 due to redirect which happens af
terwards |
| 176 appIntegration.openInfobar(window, "url-fixer-infobar-askafter", message, butt
ons, 1); |
| 177 |
| 178 require("typoSurvey").incrementCorrectionsCounter(); |
| 179 |
| 180 return prefix + domain + suffix; |
| 181 } |
| 182 |
| 183 let stringBundle = null; |
| 184 |
| 185 function getInfobarTexts() |
| 186 { |
| 187 // Randomize URI to work around bug 719376 |
| 188 if (!stringBundle) |
| 189 stringBundle = Services.strings.createBundle("chrome://" + require("info").a
ddonName + "/locale/typo.properties?" + Math.random()); |
| 190 let result = [ |
| 191 stringBundle.GetStringFromName("urlfixer.isItCorrect"), |
| 192 stringBundle.GetStringFromName("urlfixer.yes"), |
| 193 stringBundle.GetStringFromName("urlfixer.no") |
| 194 ]; |
| 195 |
| 196 getInfobarTexts = function() result; |
| 197 return getInfobarTexts(); |
| 198 } |
OLD | NEW |