summaryrefslogtreecommitdiffstats
path: root/toolkit/mozapps/extensions/test/xpinstall/slowinstall.sjs
blob: 5f767a8f49fe3b8cddd68c36d68388c1a9b3b8de (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;

Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/osfile.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");

const RELATIVE_PATH = "browser/toolkit/mozapps/extensions/test/xpinstall"
const NOTIFICATION_TOPIC = "slowinstall-complete";

/**
 * Helper function to create a JS object representing the url parameters from
 * the request's queryString.
 *
 * @param  aQueryString
 *         The request's query string.
 * @return A JS object representing the url parameters from the request's
 *         queryString.
 */
function parseQueryString(aQueryString) {
  var paramArray = aQueryString.split("&");
  var regex = /^([^=]+)=(.*)$/;
  var params = {};
  for (var i = 0, sz = paramArray.length; i < sz; i++) {
    var match = regex.exec(paramArray[i]);
    if (!match)
      throw "Bad parameter in queryString!  '" + paramArray[i] + "'";
    params[decodeURIComponent(match[1])] = decodeURIComponent(match[2]);
  }

  return params;
}

function handleRequest(aRequest, aResponse) {
  let id = +getState("ID");
  setState("ID", "" + (id + 1));

  function LOG(str) {
    dump("slowinstall.sjs[" + id + "]: " + str + "\n");
  }

  aResponse.setStatusLine(aRequest.httpVersion, 200, "OK");

  var params = { };
  if (aRequest.queryString)
    params = parseQueryString(aRequest.queryString);

  if (params.file) {
    let xpiFile = "";

    function complete_download() {
      LOG("Completing download");
      downloadPaused = false;

      try {
        // Doesn't seem to be a sane way to read using OS.File and write to an
        // nsIOutputStream so here we are.
        let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
        file.initWithPath(xpiFile);
        let stream = Cc["@mozilla.org/network/file-input-stream;1"].
                     createInstance(Ci.nsIFileInputStream);
        stream.init(file, -1, -1, stream.DEFER_OPEN + stream.CLOSE_ON_EOF);

        NetUtil.asyncCopy(stream, aResponse.bodyOutputStream, () => {
          LOG("Download complete");
          aResponse.finish();
        });
      }
      catch (e) {
        LOG("Exception " + e);
      }
    }

    let waitForComplete = new Promise(resolve => {
      function complete() {
        Services.obs.removeObserver(complete, NOTIFICATION_TOPIC);
        resolve();
      }

      Services.obs.addObserver(complete, NOTIFICATION_TOPIC, false);
    });

    aResponse.processAsync();

    OS.File.getCurrentDirectory().then(dir => {
      xpiFile = OS.Path.join(dir, ...RELATIVE_PATH.split("/"), params.file);
      LOG("Starting slow download of " + xpiFile);

      OS.File.stat(xpiFile).then(info => {
        aResponse.setHeader("Content-Type", "binary/octet-stream");
        aResponse.setHeader("Content-Length", info.size.toString());

        LOG("Download paused");
        waitForComplete.then(complete_download);
      });
    });
  }
  else if (params.continue) {
    dump("slowinstall.sjs: Received signal to complete all current downloads.\n");
    Services.obs.notifyObservers(null, NOTIFICATION_TOPIC, null);
  }
}