|
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 const CUR_WORK_DIR = "CurWorkD"; |
|
11 |
|
12 Cu.import("resource://gre/modules/NetUtil.jsm"); |
|
13 |
|
14 var gBasePath = "tests/dom/apps/tests/"; |
|
15 var gMiniManifestTemplate = "signed_app_template.webapp"; |
|
16 var gAppName = "Simple App"; |
|
17 var gDevName = "David Clarke"; |
|
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 version = ("version" in query) ? query.version : "1"; |
|
26 var app = ("app" in query) ? query.app : "valid"; |
|
27 var prevVersion = getState("version"); |
|
28 |
|
29 if (version != prevVersion) { |
|
30 setState("version", version); |
|
31 } |
|
32 var packageName = app + "_app_" + version + ".zip"; |
|
33 setState("packageName", packageName); |
|
34 var packagePath = "/" + gBasePath + "signed/" + packageName; |
|
35 setState("packagePath", packagePath); |
|
36 var packageSize = readSize(packagePath); |
|
37 |
|
38 var etag = getEtag(request, version); |
|
39 |
|
40 if (etagMatches(request, etag)) { |
|
41 dump("Etags Match. Sending 304\n"); |
|
42 response.setStatusLine(request.httpVersion, "304", "Not modified"); |
|
43 return; |
|
44 } |
|
45 response.setHeader("Etag", etag, false); |
|
46 |
|
47 // Serve the mini-manifest corresponding to the requested app version. |
|
48 var template = gBasePath + gMiniManifestTemplate; |
|
49 |
|
50 response.setHeader("Content-Type", |
|
51 "application/x-web-app-manifest+json", false); |
|
52 var manifest = makeResource(template, version, packagePath, packageSize, |
|
53 gAppName, gDevName, gDevUrl); |
|
54 response.write(manifest); |
|
55 } |
|
56 |
|
57 function getQuery(request) { |
|
58 var query = {}; |
|
59 request.queryString.split('&').forEach(function (val) { |
|
60 var [name, value] = val.split('='); |
|
61 query[decodeURIComponent(name)] = decodeURIComponent(value); |
|
62 }); |
|
63 return query; |
|
64 } |
|
65 |
|
66 function getEtag(request, version) { |
|
67 return request.queryString.replace(/[&=]/g, '-') + '-' + version; |
|
68 } |
|
69 |
|
70 function etagMatches(request, etag) { |
|
71 return request.hasHeader("If-None-Match") && |
|
72 request.getHeader("If-None-Match") == etag; |
|
73 } |
|
74 |
|
75 // File and resources helpers |
|
76 |
|
77 function readSize(path) { |
|
78 var file = Cc["@mozilla.org/file/directory_service;1"]. |
|
79 getService(Ci.nsIProperties).get(CUR_WORK_DIR, Ci.nsILocalFile); |
|
80 var split = path.split("/"); |
|
81 for (var i = 0; i < split.length; ++i) { |
|
82 file.append(split[i]); |
|
83 } |
|
84 return file.fileSize; |
|
85 } |
|
86 |
|
87 function readFile(path) { |
|
88 var file = Cc["@mozilla.org/file/directory_service;1"] |
|
89 .getService(Ci.nsIProperties) |
|
90 .get(CUR_WORK_DIR, Ci.nsILocalFile); |
|
91 var fstream = Cc["@mozilla.org/network/file-input-stream;1"] |
|
92 .createInstance(Ci.nsIFileInputStream); |
|
93 var split = path.split("/"); |
|
94 for (var i = 0; i < split.length; ++i) { |
|
95 file.append(split[i]); |
|
96 } |
|
97 fstream.init(file, -1, 0, 0); |
|
98 var data = NetUtil.readInputStreamToString(fstream, fstream.available()); |
|
99 fstream.close(); |
|
100 return data; |
|
101 } |
|
102 |
|
103 function makeResource(templatePath, version, packagePath, packageSize, |
|
104 appName, developerName, developerUrl) { |
|
105 var res = readFile(templatePath). |
|
106 replace(/VERSIONTOKEN/g, version). |
|
107 replace(/PACKAGEPATHTOKEN/g, packagePath). |
|
108 replace(/PACKAGESIZETOKEN/g, packageSize). |
|
109 replace(/NAMETOKEN/g, appName); |
|
110 return res; |
|
111 } |