diff -r 000000000000 -r 6474c204b198 dom/apps/tests/file_app.sjs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dom/apps/tests/file_app.sjs Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,136 @@ +var gBasePath = "tests/dom/apps/tests/"; +var gAppTemplatePath = "tests/dom/apps/tests/file_app.template.html"; +var gAppcacheTemplatePath = "tests/dom/apps/tests/file_cached_app.template.appcache"; +var gDefaultIcon = "default_icon"; + +function makeResource(templatePath, version, apptype) { + let icon = getState('icon') || gDefaultIcon; + var res = readTemplate(templatePath).replace(/VERSIONTOKEN/g, version) + .replace(/APPTYPETOKEN/g, apptype) + .replace(/ICONTOKEN/g, icon); + + // Hack - This is necessary to make the tests pass, but hbambas says it + // shouldn't be necessary. Comment it out and watch the tests fail. + if (templatePath == gAppTemplatePath && apptype == 'cached') { + res = res.replace('', ''); + } + + return res; +} + +function handleRequest(request, response) { + var query = getQuery(request); + + // If this is a version update, update state and return. + if ("setVersion" in query) { + setState('version', query.setVersion); + response.setHeader("Content-Type", "text/html", false); + response.setHeader("Access-Control-Allow-Origin", "*", false); + response.write('OK'); + return; + } + + if ("setIcon" in query) { + let icon = query.setIcon; + if (icon === 'DEFAULT') { + icon = null; + } + + setState('icon', icon); + + response.setHeader("Content-Type", "text/html", false); + response.setHeader("Access-Control-Allow-Origin", "*", false); + response.write('OK'); + return; + } + + // Get the app type. + var apptype = query.apptype; + if (apptype != 'hosted' && apptype != 'cached') + throw "Invalid app type: " + apptype; + + // Get the version from server state and handle the etag. + var version = Number(getState('version')); + var etag = getEtag(request, version); + dump("Server Etag: " + etag + "\n"); + + if (etagMatches(request, etag)) { + dump("Etags Match. Sending 304\n"); + response.setStatusLine(request.httpVersion, "304", "Not Modified"); + return; + } + + response.setHeader("Etag", etag, false); + if (request.hasHeader("If-None-Match")) + dump("Client Etag: " + request.getHeader("If-None-Match") + "\n"); + else + dump("No Client Etag\n"); + + // Check if we're generating a webapp manifest. + if ('getmanifest' in query) { + var template = gBasePath + 'file_' + apptype + '_app.template.webapp'; + response.setHeader("Content-Type", "application/x-web-app-manifest+json", false); + response.write(makeResource(template, version, apptype)); + return; + } + + // If apptype==cached, we might be generating the appcache manifest. + // + // NB: Among other reasons, we use the same sjs file here so that the version + // state is shared. + if (apptype == 'cached' && 'getappcache' in query) { + response.setHeader("Content-Type", "text/cache-manifest", false); + response.write(makeResource(gAppcacheTemplatePath, version, apptype)); + return; + } + + // Generate the app. + response.setHeader("Content-Type", "text/html", false); + response.write(makeResource(gAppTemplatePath, version, apptype)); +} + +function getEtag(request, version) { + return request.queryString.replace(/&/g, '-').replace(/=/g, '-') + '-' + version; +} + +function etagMatches(request, etag) { + return request.hasHeader("If-None-Match") && request.getHeader("If-None-Match") == etag; +} + +function getQuery(request) { + var query = {}; + request.queryString.split('&').forEach(function (val) { + var [name, value] = val.split('='); + query[name] = unescape(value); + }); + return query; +} + +// Copy-pasted incantations. There ought to be a better way to synchronously read +// a file into a string, but I guess we're trying to discourage that. +function readTemplate(path) { + var file = Components.classes["@mozilla.org/file/directory_service;1"]. + getService(Components.interfaces.nsIProperties). + get("CurWorkD", Components.interfaces.nsILocalFile); + var fis = Components.classes['@mozilla.org/network/file-input-stream;1']. + createInstance(Components.interfaces.nsIFileInputStream); + var cis = Components.classes["@mozilla.org/intl/converter-input-stream;1"]. + createInstance(Components.interfaces.nsIConverterInputStream); + var split = path.split("/"); + for(var i = 0; i < split.length; ++i) { + file.append(split[i]); + } + fis.init(file, -1, -1, false); + cis.init(fis, "UTF-8", 0, 0); + + var data = ""; + let (str = {}) { + let read = 0; + do { + read = cis.readString(0xffffffff, str); // read as much as we can and put it in str.value + data += str.value; + } while (read != 0); + } + cis.close(); + return data; +}