1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/mozapps/update/tests/chrome/update.sjs Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,272 @@ 1.4 +/* Any copyright is dedicated to the Public Domain. 1.5 + * http://creativecommons.org/publicdomain/zero/1.0/ 1.6 + */ 1.7 + 1.8 +/** 1.9 + * Server side http server script for application update tests. 1.10 + * 1.11 + * !IMPORTANT - Since xpcshell used by the http server is launched with -v 170 1.12 + * this file must not use features greater than JavaScript 1.7. 1.13 + */ 1.14 + 1.15 +const AUS_Cc = Components.classes; 1.16 +const AUS_Ci = Components.interfaces; 1.17 + 1.18 +#include ../sharedUpdateXML.js 1.19 + 1.20 +const URL_HOST = "http://example.com"; 1.21 +const URL_PATH_UPDATE_XML = "/chrome/toolkit/mozapps/update/tests/chrome/update.sjs"; 1.22 +const URL_HTTP_UPDATE_SJS = URL_HOST + URL_PATH_UPDATE_XML; 1.23 +const REL_PATH_DATA = "chrome/toolkit/mozapps/update/tests/data/"; 1.24 +const SERVICE_URL = URL_HOST + "/" + REL_PATH_DATA + FILE_SIMPLE_MAR; 1.25 + 1.26 +const SLOW_MAR_DOWNLOAD_INTERVAL = 100; 1.27 +var gTimer; 1.28 + 1.29 +function handleRequest(aRequest, aResponse) { 1.30 + var params = { }; 1.31 + if (aRequest.queryString) 1.32 + params = parseQueryString(aRequest.queryString); 1.33 + 1.34 + var statusCode = params.statusCode ? parseInt(params.statusCode) : 200; 1.35 + var statusReason = params.statusReason ? params.statusReason : "OK"; 1.36 + aResponse.setStatusLine(aRequest.httpVersion, statusCode, statusReason); 1.37 + aResponse.setHeader("Cache-Control", "no-cache", false); 1.38 + 1.39 + if (params.addonID) { 1.40 + aResponse.write(getUpdateRDF(params)); 1.41 + return; 1.42 + } 1.43 + 1.44 + // When a mar download is started by the update service it can finish 1.45 + // downloading before the ui has loaded. By specifying a serviceURL for the 1.46 + // update patch that points to this file and has a slowDownloadMar param the 1.47 + // mar will be downloaded asynchronously which will allow the ui to load 1.48 + // before the download completes. 1.49 + if (params.slowDownloadMar) { 1.50 + aResponse.processAsync(); 1.51 + aResponse.setHeader("Content-Type", "binary/octet-stream"); 1.52 + aResponse.setHeader("Content-Length", SIZE_SIMPLE_MAR); 1.53 + var marFile = AUS_Cc["@mozilla.org/file/directory_service;1"]. 1.54 + getService(AUS_Ci.nsIProperties). 1.55 + get("CurWorkD", AUS_Ci.nsILocalFile); 1.56 + var path = REL_PATH_DATA + FILE_SIMPLE_MAR; 1.57 + var pathParts = path.split("/"); 1.58 + for(var i = 0; i < pathParts.length; ++i) 1.59 + marFile.append(pathParts[i]); 1.60 + var contents = readFileBytes(marFile); 1.61 + gTimer = AUS_Cc["@mozilla.org/timer;1"]. 1.62 + createInstance(AUS_Ci.nsITimer); 1.63 + gTimer.initWithCallback(function(aTimer) { 1.64 + aResponse.write(contents); 1.65 + aResponse.finish(); 1.66 + }, SLOW_MAR_DOWNLOAD_INTERVAL, AUS_Ci.nsITimer.TYPE_ONE_SHOT); 1.67 + return; 1.68 + } 1.69 + 1.70 + if (params.uiURL) { 1.71 + var remoteType = ""; 1.72 + if (!params.remoteNoTypeAttr && 1.73 + (params.uiURL == "BILLBOARD" || params.uiURL == "LICENSE")) { 1.74 + remoteType = " " + params.uiURL.toLowerCase() + "=\"1\""; 1.75 + } 1.76 + aResponse.write("<html><head><meta http-equiv=\"content-type\" content=" + 1.77 + "\"text/html; charset=utf-8\"></head><body" + 1.78 + remoteType + ">" + params.uiURL + 1.79 + "<br><br>this is a test mar that will not affect your " + 1.80 + "build.</body></html>"); 1.81 + return; 1.82 + } 1.83 + 1.84 + if (params.xmlMalformed) { 1.85 + aResponse.write("xml error"); 1.86 + return; 1.87 + } 1.88 + 1.89 + if (params.noUpdates) { 1.90 + aResponse.write(getRemoteUpdatesXMLString("")); 1.91 + return; 1.92 + } 1.93 + 1.94 + if (params.unsupported) { 1.95 + aResponse.write(getRemoteUpdatesXMLString(" <update type=\"major\" " + 1.96 + "unsupported=\"true\" " + 1.97 + "detailsURL=\"" + URL_HOST + 1.98 + "\"></update>\n")); 1.99 + return; 1.100 + } 1.101 + 1.102 + var hash; 1.103 + var patches = ""; 1.104 + if (!params.partialPatchOnly) { 1.105 + hash = SHA512_HASH_SIMPLE_MAR + (params.invalidCompleteHash ? "e" : ""); 1.106 + patches += getRemotePatchString("complete", SERVICE_URL, "SHA512", 1.107 + hash, SIZE_SIMPLE_MAR); 1.108 + } 1.109 + 1.110 + if (!params.completePatchOnly) { 1.111 + hash = SHA512_HASH_SIMPLE_MAR + (params.invalidPartialHash ? "e" : ""); 1.112 + patches += getRemotePatchString("partial", SERVICE_URL, "SHA512", 1.113 + hash, SIZE_SIMPLE_MAR); 1.114 + } 1.115 + 1.116 + var type = params.type ? params.type : "major"; 1.117 + var name = params.name ? params.name : "App Update Test"; 1.118 + var appVersion = params.appVersion ? params.appVersion : "99.9"; 1.119 + var displayVersion = params.displayVersion ? params.displayVersion 1.120 + : "version " + appVersion; 1.121 + var platformVersion = params.platformVersion ? params.platformVersion : "99.8"; 1.122 + var buildID = params.buildID ? params.buildID : "01234567890123"; 1.123 + // XXXrstrong - not specifying a detailsURL will cause a leak due to bug 470244 1.124 +// var detailsURL = params.showDetails ? URL_HTTP_UPDATE_SJS + "?uiURL=DETAILS" : null; 1.125 + var detailsURL = URL_HTTP_UPDATE_SJS + "?uiURL=DETAILS"; 1.126 + var billboardURL = params.showBillboard ? URL_HTTP_UPDATE_SJS + "?uiURL=BILLBOARD" : null; 1.127 + if (billboardURL && params.remoteNoTypeAttr) 1.128 + billboardURL += "&remoteNoTypeAttr=1"; 1.129 + if (params.billboard404) 1.130 + billboardURL = URL_HOST + "/missing.html"; 1.131 + var licenseURL = params.showLicense ? URL_HTTP_UPDATE_SJS + "?uiURL=LICENSE" : null; 1.132 + if (licenseURL && params.remoteNoTypeAttr) 1.133 + licenseURL += "&remoteNoTypeAttr=1"; 1.134 + if (params.license404) 1.135 + licenseURL = URL_HOST + "/missing.html"; 1.136 + var showPrompt = params.showPrompt ? "true" : null; 1.137 + var showNever = params.showNever ? "true" : null; 1.138 + var promptWaitTime = params.promptWaitTime ? params.promptWaitTime : null; 1.139 + var showSurvey = params.showSurvey ? "true" : null; 1.140 + 1.141 + // For testing the deprecated update xml format 1.142 + if (params.oldFormat) { 1.143 + appVersion = null; 1.144 + displayVersion = null; 1.145 + billboardURL = null; 1.146 + showPrompt = null; 1.147 + showNever = null; 1.148 + showSurvey = null; 1.149 + detailsURL = URL_HTTP_UPDATE_SJS + "?uiURL=BILLBOARD"; 1.150 + if (params.remoteNoTypeAttr) 1.151 + detailsURL += "&remoteNoTypeAttr=1"; 1.152 + var extensionVersion = params.appVersion ? params.appVersion : "99.9"; 1.153 + var version = params.displayVersion ? params.displayVersion 1.154 + : "version " + extensionVersion; 1.155 + } 1.156 + 1.157 + var updates = getRemoteUpdateString(patches, type, "App Update Test", 1.158 + displayVersion, appVersion, 1.159 + platformVersion, buildID, detailsURL, 1.160 + billboardURL, licenseURL, showPrompt, 1.161 + showNever, promptWaitTime, showSurvey, 1.162 + version, extensionVersion); 1.163 + 1.164 + aResponse.write(getRemoteUpdatesXMLString(updates)); 1.165 +} 1.166 + 1.167 +/** 1.168 + * Helper function to create a JS object representing the url parameters from 1.169 + * the request's queryString. 1.170 + * 1.171 + * @param aQueryString 1.172 + * The request's query string. 1.173 + * @return A JS object representing the url parameters from the request's 1.174 + * queryString. 1.175 + */ 1.176 +function parseQueryString(aQueryString) { 1.177 + var paramArray = aQueryString.split("&"); 1.178 + var regex = /^([^=]+)=(.*)$/; 1.179 + var params = {}; 1.180 + for (var i = 0, sz = paramArray.length; i < sz; i++) { 1.181 + var match = regex.exec(paramArray[i]); 1.182 + if (!match) 1.183 + throw "Bad parameter in queryString! '" + paramArray[i] + "'"; 1.184 + params[decodeURIComponent(match[1])] = decodeURIComponent(match[2]); 1.185 + } 1.186 + 1.187 + return params; 1.188 +} 1.189 + 1.190 +/** 1.191 + * Helper function to gets the string representation of the contents of the 1.192 + * add-on's update manifest file. 1.193 + * 1.194 + * @param aParams 1.195 + * A JS object representing the url parameters from the request's 1.196 + * queryString. 1.197 + * @return A string representation of the contents of the add-on's update 1.198 + * manifest file. 1.199 + */ 1.200 +function getUpdateRDF(aParams) { 1.201 + var addonVersion; 1.202 + var addonID = aParams.addonID; 1.203 + var addonUpdateType = addonID.split("_")[0]; 1.204 + var maxVersion = aParams.platformVersion; 1.205 + 1.206 + switch (addonUpdateType) { 1.207 + case "updatecompatibility": 1.208 + // Use "1.0" for the add-on version for the compatibility update case since 1.209 + // the tests create all add-ons with "1.0" for the version. 1.210 + addonVersion = "1.0"; 1.211 + break; 1.212 + case "updateversion": 1.213 + // Use "2.0" for the add-on version for the version update case since the 1.214 + // tests create all add-ons with "1.0" for the version. 1.215 + addonVersion = "2.0"; 1.216 + break; 1.217 + default: 1.218 + return "<?xml version=\"1.0\"?>\n" + 1.219 + "<RDF:RDF xmlns:RDF=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" " + 1.220 + " xmlns:em=\"http://www.mozilla.org/2004/em-rdf#\">\n" + 1.221 + "</RDF:RDF>\n"; 1.222 + } 1.223 + 1.224 + return "<?xml version=\"1.0\"?>\n" + 1.225 + "<RDF:RDF xmlns:RDF=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" " + 1.226 + " xmlns:em=\"http://www.mozilla.org/2004/em-rdf#\">\n" + 1.227 + " <RDF:Description about=\"urn:mozilla:extension:" + addonID + "\">\n" + 1.228 + " <em:updates>\n" + 1.229 + " <RDF:Seq>\n" + 1.230 + " <RDF:li resource=\"urn:mozilla:extension:" + addonID + ":" + addonVersion + "\"/>\n" + 1.231 + " </RDF:Seq>\n" + 1.232 + " </em:updates>\n" + 1.233 + " </RDF:Description>\n" + 1.234 + " <RDF:Description about=\"urn:mozilla:extension:" + addonID + ":" + addonVersion + "\">\n" + 1.235 + " <em:version>" + addonVersion + "</em:version>\n" + 1.236 + " <em:targetApplication>\n" + 1.237 + " <RDF:Description>\n" + 1.238 + " <em:id>toolkit@mozilla.org</em:id>\n" + 1.239 + " <em:minVersion>0</em:minVersion>\n" + 1.240 + " <em:maxVersion>" + maxVersion + "</em:maxVersion>\n" + 1.241 + " <em:updateLink>" + URL_HTTP_UPDATE_SJS + "</em:updateLink>\n" + 1.242 + " <em:updateHash>sha256:0</em:updateHash>\n" + 1.243 + " </RDF:Description>\n" + 1.244 + " </em:targetApplication>\n" + 1.245 + " </RDF:Description>\n" + 1.246 + "</RDF:RDF>\n"; 1.247 +} 1.248 + 1.249 +/** 1.250 + * Reads the binary contents of a file and returns it as a string. 1.251 + * 1.252 + * @param aFile 1.253 + * The file to read from. 1.254 + * @return The contents of the file as a string. 1.255 + */ 1.256 +function readFileBytes(aFile) { 1.257 + var fis = AUS_Cc["@mozilla.org/network/file-input-stream;1"]. 1.258 + createInstance(AUS_Ci.nsIFileInputStream); 1.259 + fis.init(aFile, -1, -1, false); 1.260 + var bis = AUS_Cc["@mozilla.org/binaryinputstream;1"]. 1.261 + createInstance(AUS_Ci.nsIBinaryInputStream); 1.262 + bis.setInputStream(fis); 1.263 + var data = []; 1.264 + var count = fis.available(); 1.265 + while (count > 0) { 1.266 + var bytes = bis.readByteArray(Math.min(65535, count)); 1.267 + data.push(String.fromCharCode.apply(null, bytes)); 1.268 + count -= bytes.length; 1.269 + if (bytes.length == 0) 1.270 + throw "Nothing read from input stream!"; 1.271 + } 1.272 + data.join(''); 1.273 + fis.close(); 1.274 + return data.toString(); 1.275 +}