//********************************************************************************* // Copyright (c) Microsoft Corporation. All rights reserved. // // File Name : Redirect.js // Description : Redirection logic for determining best URL for client. // // Revisions : alias date description // pcupp 2006-12-19 updated with wuweb.dll based version check // pcupp 2006-12-30 added comments and consistent return value // also added Vista lang support // pcupp 2007-06-04 split client environment variable detection // and redirection for testability // pcupp 2007-07-10 added isSufficient check to prevent XmlHttp // requests when browser or OS is unsupported // pcupp 2007-08-23 removed unecessary constants, changed lang // check to work with firefox. //********************************************************************************* // OS types var conOSUnsupported = "-1"; var conOSWin2K = "5.0"; var conOSWinXP = "5.1"; var conOSWin2003 = "5.2"; var conOSVista = "6.0"; var conOSWin7 = "6.1"; var conOSWin8 = "6.2"; var conOSWinBlue = "6.3"; var conOSWin10 = "10.0"; // Thanks page codes var conThanksDown = 1; var conThanksBadOS = 2; var conThanksWinCE = 3; var conThanksDatacenter = 4; var conThanksBadBrowser = 5; var conThanksIE5 = 8; var conThanksLocale = 9; var conThanks64BitBrowser = 10; // URLs and related constants, keep these lower case to ensure // comparisons below are done correctly. var V3Site = "http://windowsupdate.microsoft.com" var V4Site = "http://v4.windowsupdate.microsoft.com"; var V5Site = "http://v5.windowsupdate.microsoft.com"; var V6Site = "http://www.update.microsoft.com/windowsupdate"; var V7Cat = "http://go.microsoft.com/fwlink/?LinkID=96155"; var WinBlueFWLink = "http://go.microsoft.com/fwlink/?LinkId=321527"; // Using this name so that it's easily searchable. // V6Site cursite value should be 6Live var conCurSite = "6Live"; var conRedrThanks = V6Site + "/v6/" + "thanks.aspx?" ; //================================================================================= // Environmental assessment //================================================================================= // Keeping globals around to preserve legacy behaviors outside redirection scope var g_iOSType; var g_iOSSPMajor; var g_sOSLang; var g_sUA; var g_bMUOptin; /// /// Class to determine the state of the client environment, /// which is used by the redirection function to determine the /// appropriate URL for the user. /// function ClientEnvironment() { // Capture global variable values if(typeof(curSite) != typeof(window.undefined)) this.currentSite = curSite; if(typeof(g_bMUSite) != typeof(window.undefined)) this.isCurrentSiteMU = g_bMUSite; if(typeof(g_sDownForMaintenance2K) != typeof(window.undefined)) this.isDownForMaintenance2K = g_sDownForMaintenance2K.length > 0; if(typeof(g_sDownForMaintenanceXP) != typeof(window.undefined)) this.isDownForMaintenanceXP = g_sDownForMaintenanceXP.length > 0; if(typeof(g_sDownForMaintenance2003) != typeof(window.undefined)) this.isDownForMaintenance2003 = g_sDownForMaintenance2003.length > 0; if(typeof(g_sDownForMaintenanceLonghorn) != typeof(window.undefined)) this.isDownForMaintenanceLonghorn = g_sDownForMaintenanceLonghorn.length > 0; // Save the current URL this.currentUrl = window.location.href.toLowerCase(); // Check protocol so it can be preserved prior to redirecting this.isHttps = this.currentUrl.substr(0,6) == 'https:'; // Get raw userAgent string and store it this.rawUserAgent = navigator.userAgent.toLowerCase(); // Call a helper function to determine a normalized user agent string this.userAgent = this._getUserAgent(); g_sUA = this.userAgent; // Call a helper function to determine the OS this.os = this._getOS(this.userAgent); g_iOSType = this.os; // Call a helper function to determine the language to display the site in this.langID = this._getLangID(navigator.browserLanguage ? navigator.browserLanguage : navigator.language, (this.os == conOSVista || this.os == conOSWin7 || this.os == conOSWin8 || this.os == conOSWinBlue || this.os.conOSWin10)); g_sOSLang = this.langID; // Get cpuClass directly from the navigator object if(navigator.cpuClass) this.cpuClass = navigator.cpuClass.toLowerCase(); else this.cpuClass = ""; if((this.cpuClass == "x86") && (this.userAgent.indexOf("wow") > 0)) this.cpuClass = "wow64"; // Default properties determined by the client to an undefined state // just declaring them below to make the ClientEnvironment contract // with the Redirector class clear. this.isManaged = window.undefined; this.isOptedIntoMU = window.undefined; this.servicePack = window.undefined; this.clientVersion = window.undefined; this.serviceUrl = window.undefined; this.isControlCreatable = true; // Initialize the values above by calling the helper function below this._detectClientInfo(this.os); g_bMUOptin = this.isOptedIntoMU; g_iOSSPMajor = this.servicePack; } ClientEnvironment.prototype = { /// /// Determines the user agent string for evaluating redirection. /// _getUserAgent: function() { var userAgent = ""; try { userAgent = navigator.userAgent.toLowerCase(); // make a request to the server to allow any fixup // of the navigator's UA string var xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); xmlHttp.open("POST", "redirect.asp?UA=true", false); xmlHttp.send(""); // read the response which has been delimited on the server by @| var responseXml = xmlHttp.responseText; var responseXmlParts = responseXml.split("@|"); if(responseXmlParts.length > 1) { userAgent = getSafeResponse(responseXmlParts[1].toLowerCase()); } } catch(e) { // fail silently, we can make redirection decisions // if we run into problems obtaining this data } return userAgent; }, /// /// Determine the OS. /// /// /// One of conOSWin2K, conOSWinXP, conOSWin2003, conOSVista, conOSWin7, conOSWin8, conOSWinBlue, consOSWin10 /// or conOSUnsupported according to the detected OS. /// /// Checks are based off of the contents of the user agent string. /// _getOS: function(userAgent) { // Default to unsupported var os = conOSUnsupported; // Check the UA to see what OS the user is running if(userAgent.indexOf("windows nt 5.0") > 0) os = conOSWin2K; else if(userAgent.indexOf("windows nt 5.1") > 0) os = conOSWinXP; else if(userAgent.indexOf("windows nt 5.2") > 0) os = conOSWin2003; else if(userAgent.indexOf("windows nt 6.0") > 0) os = conOSVista; else if(userAgent.indexOf("windows nt 6.1") > 0) os = conOSWin7; else if(userAgent.indexOf("windows nt 6.2") > 0) os = conOSWin8; else if (userAgent.indexOf("windows nt 6.3") > 0) os = conOSWinBlue; else if (userAgent.indexOf("windows nt 10.0") > 0) os = conOSWin10; return os; }, /// /// Given a preferred language ID translate it to a supported language ID. /// /// /// A supported language ID. /// _getLangID: function(langID, isVista) { // Normalize the langID string if(typeof(langID) == "undefined" || langID == null) { langID = "en"; } langID = langID.toLowerCase(); var allSupportedLangs; // Vista and down-level OS's have different language support if(isVista) { allSupportedLangs = "ar,cs,da,el,en,nl,fi,fr,de,he,hu,it,ja,ko,no,pl,ru,es,sv,tr,bg,hr,et,lv,lt,ro,sk,sl,th,uk,sr,"; // Switch on languages with a custom fallback switch(langID) { case "be": case "kk": case "ky": return "ru" ; case "eu": case "ca": case "qut": case "quz": return "es" ; case "zh-hk": return "zh-tw" ; case "zh-sg": return "zh-cn" ; case "fo": return "da" ; case "sz": case "nn-no": case "nb-no": return "no" ; case "sb": return "de" ; case "iw-il": return "he" ; case "el_ms": return "el" ; case "lb": return "fr"; case "tt": case "uz-uz-latn": return "ru"; } } else { allSupportedLangs = "ar,cs,da,de,el,en,es,fi,fr,he,hu,it,ja,ko,nl,no,pt,pl,ru,sv,tr,"; // Switch on languages with a custom fallback switch(langID) { case "be": case "uk": return "ru" ; case "eu": case "ca": return "es" ; case "zh-sg": return "zh-cn" ; case "fo": return "da" ; case "sz": return "no" ; case "sk": return "cs" ; case "sb": return "de" ; case "nb-no": case "nn-no": return "no" ; case "iw-il": return "he" ; } } // These are the only four region specific strings supported if((langID == "zh-tw") || (langID == "zh-cn") || (langID == "pt-br") || (langID == "zh-hk")) return langID; // All other strings are truncated to language only langID = langID.substr(0,2); // Lastly if the language string is not among the supported list fallback to en if(allSupportedLangs.search(langID + ",") < 0 ) langID = "en"; return langID; }, _detectClientInfo: function(os) { // Control variables to be nulled prior to return var control = null; var serviceManager = null; var updateServices = null; // Get the proper WU control if(os == conOSVista || os == conOSWin7 || this.os == conOSWin8 || this.os == conOSWinBlue || this.os == conOSWin10){ try{ control = new ActiveXObject("SoftwareDistribution.VistaWebControl"); } catch(e) { this.isControlCreatable = false; } } else { try { // WU control control = new ActiveXObject("SoftwareDistribution.WebControl"); } catch(e) { // Keep going this.isControlCreatable = false; } } try { // If control is present get SP level, control version, managed and opt-in settings if(control != null && typeof(control) == "object") { this.servicePack = control.GetOSVersionInfo(4,1); this.clientVersion = this._getAgentVersion(control); if(os == conOSVista || os == conOSWin7 || this.os == conOSWin8 || this.os == conOSWinBlue || this.os == conOSWin10) { if(control.GetUpdateServiceOptInStatus("7971f918-a847-4430-9279-4a52d1efe18d") || control.GetUpdateServiceOptInStatus("273d61df-59ea-46c5-8ced-c94d6dade3d1")) this.isOptedIntoMU = true; } else { serviceManager = control.CreateObject("Microsoft.Update.ServiceManager"); updateServices = serviceManager.Services; for (i = 0; i < updateServices.Count; i++) { if((updateServices.Item(i).IsRegisteredWithAU) && (!updateServices.Item(i).IsManaged) && (updateServices.Item(i).ServiceId.toLowerCase() != "9482f4b4-e343-43b6-b170-9a65bc822c77")) { this.isOptedIntoMU = true; this.serviceUrl = updateServices.Item(i).ServiceUrl; break; } } for(i = 0; i < updateServices.Count; i++) { if (updateServices.Item(i).IsManaged) { this.isManaged = true; break; } } } } } catch(e) { // If there are control problems then omit those // parameters from the request to redirect.asp // but don't stop, hence the empty catch block. } // Null control references to manage COM refernce count control = null; updateServices = null; serviceManager = null; // Null any global reference as well to preserve legacy behavior if(typeof(g_oControl) != typeof(window.undefined)) g_oControl = null; }, /// /// Gets the version (as a string) of the Windows Update agent or /// the version of the ActiveX control if that isn't available. /// Will return the empty string if neither can be obtained. /// _getAgentVersion: function(control) { var versionForRedirection = ""; var agentInfo; if(typeof(control) != "undefined" && control != null) { try { // Check AgentInfo for agent version first agentInfo = control.CreateObject("Microsoft.Update.AgentInfo"); var agentVersion = agentInfo.GetInfo("ProductVersionString"); var controlVersion = control.GetOSVersionInfo(10, 0); versionForRedirection = this._getMaxVersion(agentVersion, controlVersion); } catch(e) { try { // Get version the old way versionForRedirection = control.GetOSVersionInfo(10, 0); } catch(ignore) { // Continue with no version info (parity behavior) } } // Try to ensure the control is unloaded by IE to accomodate // self-update scenarios agentInfo = null; } return versionForRedirection; }, /// /// Gets the greater of the two version strings. Null version /// strings are treated as zero. /// _getMaxVersion: function(version1, version2) { var maxVersion; // Check for null and undefined if(typeof(version1) == "undefined" || version1 == null) version1 = "0"; if(typeof(version2) == "undefined" || version2 == null) version2 = "0"; // Coerce to strings version1 = version1 + ""; version2 = version2 + ""; // Get the parts of the version var partsVersion1 = version1.split("."); var partsVersion2 = version2.split("."); // Get the max of agent and control versions var i; for(i=0; i n2) { // version 1 larger maxVersion = version1; break; }else if(n2 > n1) { // version 2 larger maxVersion = version2; break; } } if(i==partsVersion1.length || i==partsVersion2.length) { // Equal but different lengths, return the longer of the two if(partsVersion1.length > partsVersion2.length) { maxVersion = version1; }else { maxVersion = version2; } } return maxVersion; } }; //================================================================================= // Redirection logic //================================================================================= // Preserve legacy behavior with these global vars var g_bV4Catalog = false; /// /// This class tracks checks performed against the client /// environment and allows any given check to determine /// that it is sufficent and no other checks should be /// performed and also set a URL if applicable to which /// the user should be redirected. A null destinationUrl /// with isSufficient=true, for example, indicates that /// the browser may stay at the current URL and no further /// checks are necessary. /// function RedirectorDestination() { this.isSufficient = false; this.destinationUrl = null; } /// /// Facilitates redirection after assessing client environment /// variables. /// function Redirector(clientEnvironment) { this.clientEnvironment = clientEnvironment; // Get a new querystring that has been sanitized and stripped of lang settings this.safeQueryString = this._getSafeQueryStringFromUrl(this.clientEnvironment.currentUrl); // Preserve legacy behavior and set global to indicate if this is the V4 Catalog site this.isV4Catalog = (this.clientEnvironment.currentUrl.search("/catalog") > 0) && (this.clientEnvironment.currentSite == 4); g_bV4Catalog = this.isV4Catalog; //get the IE version number //we will use this later to check supported IE versions and special casing for IE 7 or greater this.ieVersion = 0; var regexResult = /MSIE ([1-9]+([0-9]*)(\.[0-9]+))/i.exec(this.clientEnvironment.userAgent); if (regexResult != null) { this.ieVersion = regexResult[1]; } else { var regexResult = /IE ([1-9]+([0-9]*)(\.[0-9]+))/i.exec(this.clientEnvironment.userAgent); if (regexResult != null) { this.ieVersion = regexResult[1]; } else // In Win10, IE version isn't displayed as part of the userAgent string, so figure out if it is IE or Edge { var regexResult = /Windows NT ([1]+([0-9]+)(\.[0-9]+))/i.exec(this.clientEnvironment.userAgent); if (regexResult != null) { if (this.clientEnvironment.userAgent.indexOf("edge") == -1) // It is IE { this.ieVersion = 11; } } } } } Redirector.prototype = { /// /// Jump to url and ensure all references in the target /// URL to the http protocol are replaced with https /// if the useHttps flag is true. /// /// /// false if redirection not occuring and true otherwise. /// /// /// This function may return without redirecting if the /// currentUrl is already the intended URL to prevent /// infinite redirection. /// /// Script can continue executing after setting the /// location property of the window object. Callers /// should take care that this behavior doesn't cause /// unintended side effects. /// redirect: function(url, useHttps) { // Return value var isRedirectionOccurring = false; if(!url) return isRedirectionOccurring; if(url.indexOf(V3Site) > -1 && this.clientEnvironment.currentSite == 3) { isRedirectionOccurring = true; this._writeV3Frameset(); } else { var urlWithProtocolFixup = this._swapProtocol(url, useHttps); // Only redirect if we aren't already at the intended destination if(this._getBaseUrl(urlWithProtocolFixup) != this._getBaseUrl(this.clientEnvironment.currentUrl)) { isRedirectionOccurring = true; location.href = urlWithProtocolFixup; } } return isRedirectionOccurring; }, /// /// Writes proper frameset for the V3 site. /// _writeV3Frameset: function() { document.open(); document.write(""); if(this.clientEnvironment.userAgent.indexOf("windows 95") > 0) { // Windows 95 document.write(""); }else{ // Windows NT if(location.search == "" || location.search == null) { document.write(""); }else{ document.write(""); } } document.write(""); document.close(); }, /// /// Replace all occurrences of http with https protocol if /// useHttps is true. /// /// /// Pattern matches all instances of http: to pick up embedded /// URLs in querystrings as well. /// _swapProtocol: function(url, useHttps) { var urlWithProtocolFixup = url; if(useHttps) { // replace any instance of http: anywhere with https: // this covers returnUrl in QS as well as actual protocol of destination URL var regExp = /http:/g; urlWithProtocolFixup = urlWithProtocolFixup.replace(regExp, "https:"); } return urlWithProtocolFixup; }, /// /// Get the base portion of the URL (up to but not including /// the querystring). /// /// /// Base portion of the URL. /// /// /// Empty string is returned if arguments are invalid. /// _getBaseUrl: function(url) { var baseUrl = url; if(url != null && typeof(url) == typeof("")) { var qsIndex = url.indexOf("?"); if(qsIndex > -1) { baseUrl = url.substring(0, qsIndex); } // Don't let trailing slashes alter the comparison if(baseUrl.substring(baseUrl.length-1) == "/") { baseUrl = baseUrl.substring(0, baseUrl.length-1); } baseUrl = baseUrl.toLowerCase(); } return baseUrl; }, /// /// Scrub the querystring in the provided url and return it. /// _getSafeQueryStringFromUrl: function(url) { var qsCleaned = ""; if(typeof(url) == typeof("") && url != null && url.indexOf("?") > -1) { var qsTemp = url.split("?")[1]; var qsParts = qsTemp.split("&"); for(var i= 0; i < qsParts.length; i++){ if(qsParts[i].toLowerCase().substr(0, 3) != "ln=" && qsParts[i].toLowerCase().substr(0, 10) != "returnurl=") { qsCleaned += qsParts[i] + "&"; } } qsCleaned = qsCleaned.substr(0, qsCleaned.length-1); } return qsCleaned; }, /// /// Determine the destination when the site is down for maintenance. /// This check is sufficient to determine the final destination when /// the site destination is down. /// /// /// This function does not apply when on the v3 or v4 sites. /// _getV5DownForMaintenanceUrl: function(redirectorDestination) { // Short circuit if prior checks sufficient if(redirectorDestination.isSufficient) return; // Shortcut var var client = this.clientEnvironment; // V5 - Check the down-for-maintenance indicator if(client.currentSite != "3" && client.currentSite != "4" ) { var urlTemp = conRedrThanks + "ln=" + client.langID + "&thankspage=" + conThanksDown + "&os="; try{ if(client.userAgent.indexOf("windows nt 5.0") > 0 && client.isDownForMaintenance2K) { redirectorDestination.destinationUrl = urlTemp + conOSWin2K + "&" + this.safeQueryString; redirectorDestination.isSufficient = true; } else if(client.userAgent.indexOf("windows nt 5.1") > 0 && client.isDownForMaintenanceXP) { redirectorDestination.destinationUrl = urlTemp + conOSWinXP + "&" + this.safeQueryString; redirectorDestination.isSufficient = true; } else if(client.userAgent.indexOf("windows nt 5.2") > 0 && client.isDownForMaintenance2003) { redirectorDestination.destinationUrl = urlTemp + conOSWin2003 + "&" + this.safeQueryString; redirectorDestination.isSufficient = true; } else if ((client.userAgent.indexOf("windows nt 6.0") > 0 || client.userAgent.indexOf("windows nt 6.1") > 0 || client.userAgent.indexOf("windows nt 6.2") > 0 || client.userAgent.indexOf("windows nt 6.3") > 0 || client.userAgent.indexOf("windows nt 10.0") > 0) && client.isDownForMaintenanceLonghorn) { redirectorDestination.destinationUrl = urlTemp + conOSVista + "&" + this.safeQueryString; redirectorDestination.isSufficient = true; } } catch(e) { // squash all errors and continue } } }, /// /// Determine the destination when the user is using WinCE. /// This check is sufficient for WinCE machines to determine /// a final destination. /// _getWinCEUrl: function(redirectorDestination) { // Short circuit if prior checks sufficient if(redirectorDestination.isSufficient) return; // Check for Windows CE if(this.clientEnvironment.userAgent.indexOf("; mspie") != -1) { // Windows CE thanks page redirectorDestination.isSufficient = true; redirectorDestination.destinationUrl = conRedrThanks + "ln=" + this.clientEnvironment.langID + "&thankspage=" + conThanksWinCE + "&" + this.safeQueryString; } }, /// /// Determine the destination when the user is using 2K Datacenter. /// This check is sufficient for 2K Datacenter machines when not /// on the V4 catalog site. /// _getDatacenterUrl: function(redirectorDestination) { // Short circuit if prior checks sufficient if(redirectorDestination.isSufficient) return; // Shortcut vars var userAgent = this.clientEnvironment.userAgent; // Check for Windows 2000 Datacenter if((userAgent.indexOf("windows nt 5.0") != -1) && (userAgent.indexOf("; data center") != -1)) { if(!this.isV4Catalog) { // Windows 2000 Datacenter thanks page if they aren't already on the catalog (since that is also // a supported datacenter scenario and we shouldn't redirect user to consumer site from catalog). redirectorDestination.destinationUrl = conRedrThanks + "ln=" + this.clientEnvironment.langID + "&thankspage=" + conThanksDatacenter + "&" + this.safeQueryString; redirectorDestination.isSufficient = true; } } }, /// /// Check if this is Win10+ and set redirect accordingly /// _getWin10PlusBrowserUrl: function (redirectorDestination) { // Short circuit if prior checks sufficient if (redirectorDestination.isSufficient) return; // Shortcut vars var userAgent = this.clientEnvironment.userAgent; var regexResult = /Windows NT ([1]+([0-9]+)(\.[0-9]+))/i.exec(this.clientEnvironment.userAgent); if (regexResult != null) { redirectorDestination.destinationUrl = WinBlueFWLink; // Redirect to this webpage for Edge & IE on Win10. Doing this for IE too because on Win10, IE can't get the controlVersion redirectorDestination.isSufficient = true; } }, /// /// Determine the destination based on the user's browser. /// This check is sufficient to determine the final destination /// for unsupported browsers. /// _getBrowserUrl: function(redirectorDestination) { // Short circuit if prior checks sufficient if(redirectorDestination.isSufficient) return; // Shortcut vars var userAgent = this.clientEnvironment.userAgent; var rawUserAgent = this.clientEnvironment.rawUserAgent; var isSupportedIEVersion = this.ieVersion >= 5; var isUnsupportedBrowser = false; if(userAgent.indexOf("opera/") != -1 || userAgent.indexOf(" opera ") != -1) isUnsupportedBrowser = true; // If we know it's not IE or is on the specifically unsupported list then // return a browerUrl if(!isSupportedIEVersion || isUnsupportedBrowser) { redirectorDestination.destinationUrl = conRedrThanks + "ln=" + this.clientEnvironment.langID + "&" + this.safeQueryString + "&thankspage=" + conThanksBadBrowser; redirectorDestination.isSufficient=true; } }, /// /// Determine the destination when the user is using 95 or NT. /// This check is sufficient to determine the final destination /// for those operating systems. /// /// /// Note that a V3 url will get special handling during the redirect method. /// _get95NT4Url: function(redirectorDestination) { // Short circuit if prior checks sufficient if(redirectorDestination.isSufficient) return; // Shortcut var var userAgent = this.clientEnvironment.userAgent; if((userAgent.indexOf("windows 95") > 0) || ( userAgent.indexOf("windows nt)") >0 ) || ( userAgent.indexOf("windows nt;") >0 ) || ( userAgent.indexOf("windows nt 4") > 0 ) ) { redirectorDestination.destinationUrl = V3Site + "?" + this.safeQueryString; redirectorDestination.isSufficient = true; } }, /// /// Determine the destination when the user is using 98. /// This check is sufficient to determine the final destination /// for those operating systems though a destination URL may not /// be set in all 98 cases to allow the user to remain on the V4 /// Catalog. /// _get98Url: function(redirectorDestination) { // Short circuit if prior checks sufficient if(redirectorDestination.isSufficient) return; if(this.clientEnvironment.userAgent.indexOf("windows 98") > 0) { // This check is sufficient if the OS is 98 regardless of whether we // determine if redirection is necessary. redirectorDestination.isSufficient = true; if (this.clientEnvironment.currentSite != 4) { redirectorDestination.destinationUrl = V4Site + "?" + this.safeQueryString; } } }, /// /// Determine a destination for any OS that is unsupported. /// This check is sufficient to determine the final destination /// for unsupported operating systems. /// /// _getUnsupportedOSUrl: function(redirectorDestination) { // Short circuit if prior checks sufficient if(redirectorDestination.isSufficient) return; if (this.clientEnvironment.os == conOSUnsupported) { redirectorDestination.destinationUrl = conRedrThanks + "ln=" + this.clientEnvironment.langID + "&thankspage=" + conThanksBadOS + "&" + this.safeQueryString; redirectorDestination.isSufficient = true; } }, /// /// Get V4Site destination for Windows XP, Server 2K3 or Windows XP x64 Edition /// when the processor is 64-bit and the service pack level is either undetermined /// (likely due to client control problems) or is 0 - meaning SP level is RTM. /// This check is sufficient in determining the final destination for the scenarios /// listed above. /// _get64MUUrl: function(redirectorDestination){ // Short circuit if prior checks sufficient if(redirectorDestination.isSufficient) return; // Shortcut var var client = this.clientEnvironment; // If this is the MU site and we are on a down-level OS if(client.isCurrentSiteMU && (client.os != conOSVista || client.os != conOSWin7 || client.os != conOSWin8 || client.os != conOSWinBlue || client.os != conOSWin10)) { if( (client.userAgent.indexOf("windows nt 5.1") > 0 || client.userAgent.indexOf("windows nt 5.2") > 0) && (client.servicePack == "" || client.servicePack == 0) && (client.cpuClass == "ia64" || client.cpuClass == "wow64")) { redirectorDestination.destinationUrl = V4Site + "?" + this.safeQueryString; redirectorDestination.isSufficient = true; } } }, /// /// Modifies a url to replace all instances of "MicrosoftUpdate" with /// "WindowsUpdate". /// /// /// This is only used when IEMode = noaddon /// changeMUToWUURL: function (url) { //if we're at an "ok" place, return null if (url == 'ok') { return null; } //otherwise replace microsoftupdate with windowsupdate var correctUrl = url.replace(/MicrosoftUpdate/i, "WindowsUpdate"); return correctUrl; }, /// /// Determine and return the best URL for the user given /// a collection of environmental variables. /// getDestinationUrl: function() { // Return value var redirectorDestination = new RedirectorDestination(); // Shortcut var var client = this.clientEnvironment; // Make initial checks using each of the helper functions, order is important // since earlier checks may indicate that they are sufficient and bypass later // checks this._getV5DownForMaintenanceUrl(redirectorDestination); this._getWinCEUrl(redirectorDestination); this._getDatacenterUrl(redirectorDestination); this._getWin10PlusBrowserUrl(redirectorDestination); this._getBrowserUrl(redirectorDestination); this._get95NT4Url(redirectorDestination); this._get98Url(redirectorDestination); this._getUnsupportedOSUrl(redirectorDestination); this._get64MUUrl(redirectorDestination); // Don't redirect when the following flag is set if(client.currentUrl.indexOf("g_sconsumersite") > -1) { return null; } // If the tests above are sufficient to determine the destination // ignore the remaining special cases if(!redirectorDestination.isSufficient) { // V4 catalog visitors are handled as a special case due to // V4 catalog end of life approaching if(!this.isV4Catalog){ try { var qs = "OS=" + client.os + "&Processor=" + client.cpuClass + "&Lang=" + client.langID; if(client.currentUrl.indexOf("betathanksurl") > -1) { qs += "&BetaThanksurl=true"; } if(!client.isControlCreatable && (client.os == conOSVista || client.os == conOSWin7 || client.os == conOSWin8 || client.os == conOSWinBlue || client.os == conOSWin10)) // Setting the current site to blank if the vista control is not present // so the user is taken to the WU site qs += "&CurrentSite="; else qs += "&CurrentSite=" + client.currentSite; if(client.servicePack) qs += "&SP=" + client.servicePack; if(client.clientVersion) qs += "&control=" + client.clientVersion; if(client.isOptedIntoMU) qs += "&MUOptIn=true"; if(client.isManaged) qs += "&IsManaged=true"; //send the querystring data to redirect.asp var xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); xmlHttp.open("POST", "redirect.asp?" + qs , false); xmlHttp.send("Querystring"); var responseXml = xmlHttp.responseText; //the URL is delimited bt @| so when we get the xml back split it by @| and get the url var responseUrl = ""; var responseXmlParts = responseXml.split("@|"); if(responseXmlParts.length > 1) { responseUrl = getSafeResponse(responseXmlParts[1]); } else { responseUrl = conRedrThanks + "ln=" + client.langID; } // Ensure destinationUrl is lower-cased for all comparisons below responseUrl = responseUrl.toLowerCase(); //If from IE7.0 and not on Vista if((client.os != conOSVista || client.os != conOSWin7 || client.os != conOSWin8 || client.os != conOSWinBlue || client.os != conOSWin10) && this.ieVersion >= 7 //doesn't belong on thanks page or on V4 or V5 && responseUrl.indexOf("thanks") == -1 && responseUrl.indexOf("v4.") == -1 && responseUrl.indexOf("v5.") == -1 //and contains the iemode=noaddon querystring parameter && this.clientEnvironment.currentUrl.indexOf("iemode=noaddon") > -1 ) { redirectorDestination.destinationUrl = this.changeMUToWUURL(responseUrl); if (redirectorDestination.destinationUrl != null) { redirectorDestination.destinationUrl += ("?" + this.safeQueryString); } redirectorDestination.isSufficient = true; } // If the service URL applies (in scenarios where user arrives on // WU site but is opted in) we need to redirect to the URL that // corresponsds to that opted-in service. if(!redirectorDestination.isSufficient && responseUrl == "service url") { if(typeof(client.serviceUrl) == typeof("") && client.serviceUrl.length > 0) { redirectorDestination.destinationUrl = serviceUrl; }else{ // If we didn't find a service URL then go to the thanks page redirectorDestination.destinationUrl = conRedrThanks + "ln=" + client.langID; } redirectorDestination.isSufficient = true; } // Only need to provide a destination URL when the responseUrl is not "ok" if(!redirectorDestination.isSufficient && responseUrl != "ok") { if(this.safeQueryString.length > 0) { if(responseUrl.indexOf("?") > -1) { redirectorDestination.destinationUrl = responseUrl + "&" + this.safeQueryString; } else { redirectorDestination.destinationUrl = responseUrl + "?" + this.safeQueryString; } } else { redirectorDestination.destinationUrl = responseUrl; } redirectorDestination.isSufficient = true; } } catch (e) { // Leave the user on the URL they requested if an // unexpected exception occurred in the script redirectorDestination.destinationUrl = null; redirectorDestination.isSufficient = true; } } //If V4 Catalog else { // If on vista Redirect directly to V7Cat. if(client.os == conOSVista || client.os == conOSWin7 || client.os == conOSWin8 || client.os == conOSWinBlue || client.os == conOSWin10){ redirectorDestination.destinationUrl = V7Cat; } // If they come to catalog on winxp, win2k3, win2k // and haven't been to this page previously then give them thanks page else if(client.os == conOSWin2K || client.os == conOSWinXP || client.os == conOSWin2003) { redirectorDestination.destinationUrl = V7Cat; } } } // Return the destinationUrl as determined by the various checks in this function return this._swapProtocol(redirectorDestination.destinationUrl, this.clientEnvironment.isHttps); } }; //================================================================================= // Shared Function //================================================================================= /// /// Strips the response of any values that could inject bad /// script into our site and cleans it prior to use. /// /// /// Client script cannot reliably scrub out bad response settings /// as injected script could rewrite JS functions on the client /// prior to it ever scrubbing anything making it a noop. /// However, having these types of checks throughout the server /// and client code offers multiple layers of defense. /// function getSafeResponse(responseUrl) { if (responseUrl.length > 255) { responseUrl = responseUrl.substring(0,255); } // need to remove document.write & response.write while(responseUrl.indexOf("document.write") > -1) { responseUrl = responseUrl.replace("document.write",""); } while(responseUrl.indexOf("response.write") > -1) { responseUrl = responseUrl.replace("response.write",""); } while(responseUrl.indexOf("<%") > -1) { responseUrl = responseUrl.replace("<%",""); } while(responseUrl.indexOf("%>") > -1) { responseUrl = responseUrl.replace("%>",""); } return responseUrl; } function fnRedirect() { var clientEnvironment = new ClientEnvironment(); var redirector = new Redirector(clientEnvironment); var destinationUrl = redirector.getDestinationUrl(); if(null != destinationUrl) redirector.redirect(destinationUrl); } fnRedirect();