|
1 var Cc = Components.classes; |
|
2 var Ci = Components.interfaces; |
|
3 var Cu = Components.utils; |
|
4 |
|
5 // From prio.h |
|
6 const PR_RDWR = 0x04; |
|
7 const PR_CREATE_FILE = 0x08; |
|
8 const PR_TRUNCATE = 0x20; |
|
9 |
|
10 Cu.import("resource://gre/modules/FileUtils.jsm"); |
|
11 Cu.import("resource://gre/modules/NetUtil.jsm"); |
|
12 |
|
13 var gBasePath = "tests/dom/apps/tests/"; |
|
14 var gMiniManifestTemplate = "file_packaged_app.template.webapp"; |
|
15 var gAppTemplate = "file_packaged_app.template.html"; |
|
16 var gAppName = "appname"; |
|
17 var gDevName = "devname"; |
|
18 var gDevUrl = "http://dev.url"; |
|
19 |
|
20 function handleRequest(request, response) { |
|
21 var query = getQuery(request); |
|
22 |
|
23 response.setHeader("Access-Control-Allow-Origin", "*", false); |
|
24 |
|
25 var packageSize = ("packageSize" in query) ? query.packageSize : 0; |
|
26 var appName = ("appName" in query) ? query.appName : gAppName; |
|
27 var devName = ("devName" in query) ? query.devName : gDevName; |
|
28 var devUrl = ("devUrl" in query) ? query.devUrl : gDevUrl; |
|
29 |
|
30 // If this is a version update, update state, prepare the manifest, |
|
31 // the application package and return. |
|
32 if ("setVersion" in query) { |
|
33 var version = query.setVersion; |
|
34 setState("version", version); |
|
35 var packageVersion = ("dontUpdatePackage" in query) ? version - 1 : version; |
|
36 var packageName = "test_packaged_app_" + packageVersion + ".zip"; |
|
37 |
|
38 setState("packageName", packageName); |
|
39 var packagePath = "/" + gBasePath + "file_packaged_app.sjs?getPackage=" + |
|
40 packageName; |
|
41 setState("packagePath", packagePath); |
|
42 |
|
43 if (version == packageVersion) { |
|
44 // Create the application package. |
|
45 var zipWriter = Cc["@mozilla.org/zipwriter;1"] |
|
46 .createInstance(Ci.nsIZipWriter); |
|
47 var zipFile = FileUtils.getFile("TmpD", [packageName]); |
|
48 zipWriter.open(zipFile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE); |
|
49 |
|
50 // We want to run some tests without the manifest included in the zip. |
|
51 if (version != "0") { |
|
52 var manifestTemplate = gBasePath + gMiniManifestTemplate; |
|
53 var manifest = makeResource(manifestTemplate, version, packagePath, |
|
54 packageSize, appName, devName, devUrl); |
|
55 addZipEntry(zipWriter, manifest, "manifest.webapp"); |
|
56 } |
|
57 |
|
58 var appTemplate = gBasePath + gAppTemplate; |
|
59 var app = makeResource(appTemplate, version, packagePath, packageSize, |
|
60 appName, devName, devUrl); |
|
61 addZipEntry(zipWriter, app, "index.html"); |
|
62 |
|
63 zipWriter.close(); |
|
64 } |
|
65 |
|
66 response.setHeader("Content-Type", "text/html", false); |
|
67 response.write("OK"); |
|
68 return; |
|
69 } |
|
70 |
|
71 // Get the version from server state |
|
72 var version = Number(getState("version")); |
|
73 var packageName = String(getState("packageName")); |
|
74 var packagePath = String(getState("packagePath")); |
|
75 |
|
76 var etag = getEtag(request, version); |
|
77 |
|
78 if (etagMatches(request, etag)) { |
|
79 dump("Etags Match. Sending 304\n"); |
|
80 response.setStatusLine(request.httpVersion, "304", "Not modified"); |
|
81 return; |
|
82 } |
|
83 |
|
84 response.setHeader("Etag", etag, false); |
|
85 |
|
86 // Serve the application package corresponding to the requested app version. |
|
87 if ("getPackage" in query) { |
|
88 var resource = readFile(packageName, true); |
|
89 response.setHeader("Content-Type", |
|
90 "Content-Type: application/java-archive", false); |
|
91 response.write(resource); |
|
92 return; |
|
93 } |
|
94 |
|
95 // Serve the mini-manifest corresponding to the requested app version. |
|
96 if ("getManifest" in query) { |
|
97 var template = gBasePath + gMiniManifestTemplate; |
|
98 if (!("noManifestContentType" in query)) { |
|
99 response.setHeader("Content-Type", |
|
100 "application/x-web-app-manifest+json", false); |
|
101 } |
|
102 packagePath = "wrongPackagePath" in query ? "" : packagePath; |
|
103 var manifest = makeResource(template, version, packagePath, packageSize, |
|
104 appName, devName, devUrl); |
|
105 response.write(manifest); |
|
106 return; |
|
107 } |
|
108 |
|
109 response.setHeader("Content-type", "text-html", false); |
|
110 response.write("KO"); |
|
111 } |
|
112 |
|
113 function getQuery(request) { |
|
114 var query = {}; |
|
115 request.queryString.split('&').forEach(function (val) { |
|
116 var [name, value] = val.split('='); |
|
117 query[name] = unescape(value); |
|
118 }); |
|
119 return query; |
|
120 } |
|
121 |
|
122 function getEtag(request, version) { |
|
123 return request.queryString.replace(/&/g, '-').replace(/=/g, '-') + |
|
124 '-' + version; |
|
125 } |
|
126 |
|
127 function etagMatches(request, etag) { |
|
128 return request.hasHeader("If-None-Match") && |
|
129 request.getHeader("If-None-Match") == etag; |
|
130 } |
|
131 |
|
132 // File and resources helpers |
|
133 |
|
134 function addZipEntry(zipWriter, entry, entryName) { |
|
135 var stream = Cc["@mozilla.org/io/string-input-stream;1"] |
|
136 .createInstance(Ci.nsIStringInputStream); |
|
137 stream.setData(entry, entry.length); |
|
138 zipWriter.addEntryStream(entryName, Date.now(), |
|
139 Ci.nsIZipWriter.COMPRESSION_BEST, stream, false); |
|
140 } |
|
141 |
|
142 function readFile(path, fromTmp) { |
|
143 var dir = fromTmp ? "TmpD" : "CurWorkD"; |
|
144 var file = Cc["@mozilla.org/file/directory_service;1"] |
|
145 .getService(Ci.nsIProperties) |
|
146 .get(dir, Ci.nsILocalFile); |
|
147 var fstream = Cc["@mozilla.org/network/file-input-stream;1"] |
|
148 .createInstance(Ci.nsIFileInputStream); |
|
149 var split = path.split("/"); |
|
150 for(var i = 0; i < split.length; ++i) { |
|
151 file.append(split[i]); |
|
152 } |
|
153 fstream.init(file, -1, 0, 0); |
|
154 var data = NetUtil.readInputStreamToString(fstream, fstream.available()); |
|
155 fstream.close(); |
|
156 return data; |
|
157 } |
|
158 |
|
159 function makeResource(templatePath, version, packagePath, packageSize, |
|
160 appName, developerName, developerUrl) { |
|
161 var res = readFile(templatePath, false) |
|
162 .replace(/VERSIONTOKEN/g, version) |
|
163 .replace(/PACKAGEPATHTOKEN/g, packagePath) |
|
164 .replace(/PACKAGESIZETOKEN/g, packageSize) |
|
165 .replace(/NAMETOKEN/g, appName) |
|
166 .replace(/DEVELOPERTOKEN/g, developerName) |
|
167 .replace(/DEVELOPERURLTOKEN/g, developerUrl); |
|
168 return res; |
|
169 } |