content/media/test/cancellable_request.sjs

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/content/media/test/cancellable_request.sjs	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,154 @@
     1.4 +function parseQuery(request, key) {
     1.5 +  var params = request.queryString.split('&');
     1.6 +  for (var j = 0; j < params.length; ++j) {
     1.7 +    var p = params[j];
     1.8 +	if (p == key)
     1.9 +	  return true;
    1.10 +    if (p.indexOf(key + "=") == 0)
    1.11 +	  return p.substring(key.length + 1);
    1.12 +	if (p.indexOf("=") < 0 && key == "")
    1.13 +	  return p;
    1.14 +  }
    1.15 +  return false;
    1.16 +}
    1.17 +
    1.18 +function push32BE(array, input) {
    1.19 +  array.push(String.fromCharCode((input >> 24) & 0xff));
    1.20 +  array.push(String.fromCharCode((input >> 16) & 0xff));
    1.21 +  array.push(String.fromCharCode((input >> 8) & 0xff));
    1.22 +  array.push(String.fromCharCode((input) & 0xff));
    1.23 +}
    1.24 +
    1.25 +function push32LE(array, input) {
    1.26 +  array.push(String.fromCharCode((input) & 0xff));
    1.27 +  array.push(String.fromCharCode((input >> 8) & 0xff));
    1.28 +  array.push(String.fromCharCode((input >> 16) & 0xff));
    1.29 +  array.push(String.fromCharCode((input >> 24) & 0xff));
    1.30 +}
    1.31 +
    1.32 +function push16LE(array, input) {
    1.33 +  array.push(String.fromCharCode((input) & 0xff));
    1.34 +  array.push(String.fromCharCode((input >> 8) & 0xff));
    1.35 +}
    1.36 +
    1.37 +function buildWave(samples, sample_rate) {
    1.38 +  const RIFF_MAGIC = 0x52494646;
    1.39 +  const WAVE_MAGIC = 0x57415645;
    1.40 +  const FRMT_MAGIC = 0x666d7420;
    1.41 +  const DATA_MAGIC = 0x64617461;
    1.42 +  const RIFF_SIZE = 44;
    1.43 +
    1.44 +  var header = [];
    1.45 +  push32BE(header, RIFF_MAGIC);
    1.46 +  push32LE(header, RIFF_SIZE + samples.length * 2);
    1.47 +  push32BE(header, WAVE_MAGIC);
    1.48 +  push32BE(header, FRMT_MAGIC);
    1.49 +  push32LE(header, 16);
    1.50 +  push16LE(header, 1);
    1.51 +  push16LE(header, 1);
    1.52 +  push32LE(header, sample_rate);
    1.53 +  push32LE(header, sample_rate);
    1.54 +  push16LE(header, 2);
    1.55 +  push16LE(header, 16);
    1.56 +  push32BE(header, DATA_MAGIC);
    1.57 +  push32LE(header, samples.length * 2);
    1.58 +  for (var i = 0; i < samples.length; ++i) {
    1.59 +    push16LE(header, samples[i], 2);
    1.60 +  }
    1.61 +  return header;
    1.62 +}
    1.63 +
    1.64 +const Ci = Components.interfaces;
    1.65 +const CC = Components.Constructor;
    1.66 +const Timer = CC("@mozilla.org/timer;1", "nsITimer", "initWithCallback");
    1.67 +const BinaryOutputStream = CC("@mozilla.org/binaryoutputstream;1",
    1.68 +                             "nsIBinaryOutputStream",
    1.69 +                             "setOutputStream");
    1.70 +
    1.71 +function poll(f) {
    1.72 +  if (f()) {
    1.73 +    return;
    1.74 +  }
    1.75 +  new Timer(function() { poll(f); }, 100, Ci.nsITimer.TYPE_ONE_SHOT);
    1.76 +}
    1.77 +
    1.78 +function handleRequest(request, response)
    1.79 +{
    1.80 +  var cancel = parseQuery(request, "cancelkey");
    1.81 +  if (cancel) {
    1.82 +    setState(cancel[1], "cancelled");
    1.83 +    response.setStatusLine(request.httpVersion, 200, "OK");
    1.84 +    response.write("Cancel approved!");
    1.85 +    return;
    1.86 +  }
    1.87 +
    1.88 +  var samples = [];
    1.89 +  for (var i = 0; i < 1000000; ++i) {
    1.90 +    samples.push(0);
    1.91 +  }
    1.92 +  var bytes = buildWave(samples, 44100).join("");
    1.93 +
    1.94 +  var key = parseQuery(request, "key");
    1.95 +  response.setHeader("Content-Type", "audio/x-wav");
    1.96 +  response.setHeader("Content-Length", ""+bytes.length, false);
    1.97 +
    1.98 +  var out = new BinaryOutputStream(response.bodyOutputStream);
    1.99 +
   1.100 +  var start = 0, end = bytes.length - 1;
   1.101 +  if (request.hasHeader("Range"))
   1.102 +  {
   1.103 +    var rangeMatch = request.getHeader("Range").match(/^bytes=(\d+)?-(\d+)?$/);
   1.104 +
   1.105 +    if (rangeMatch[1] !== undefined)
   1.106 +      start = parseInt(rangeMatch[1], 10);
   1.107 +
   1.108 +    if (rangeMatch[2] !== undefined)
   1.109 +      end = parseInt(rangeMatch[2], 10);
   1.110 +
   1.111 +    // No start given, so the end is really the count of bytes from the
   1.112 +    // end of the file.
   1.113 +    if (start === undefined)
   1.114 +    {
   1.115 +      start = Math.max(0, bytes.length - end);
   1.116 +      end   = bytes.length - 1;
   1.117 +    }
   1.118 +
   1.119 +    // start and end are inclusive
   1.120 +    if (end === undefined || end >= bytes.length)
   1.121 +      end = bytes.length - 1;
   1.122 +
   1.123 +    if (end < start)
   1.124 +    {
   1.125 +      response.setStatusLine(request.httpVersion, 200, "OK");
   1.126 +      start = 0;
   1.127 +      end = bytes.length - 1;
   1.128 +    }
   1.129 +    else
   1.130 +    {
   1.131 +      response.setStatusLine(request.httpVersion, 206, "Partial Content");
   1.132 +      var contentRange = "bytes " + start + "-" + end + "/" + bytes.length;
   1.133 +      response.setHeader("Content-Range", contentRange);
   1.134 +    }
   1.135 +  }
   1.136 +  
   1.137 +  if (start > 0) {
   1.138 +    // Send all requested data
   1.139 +    out.write(bytes.slice(start, end + 1), end + 1 - start);
   1.140 +    return;
   1.141 +  }
   1.142 +
   1.143 +  // Write the first 1.2M of the Wave file. We know the cache size is set to
   1.144 +  // 100K so this will fill the cache and and cause a "suspend" event on
   1.145 +  // the loading element.
   1.146 +  out.write(bytes, 1200000);
   1.147 +
   1.148 +  response.processAsync();
   1.149 +  // Now wait for the message to cancel this response
   1.150 +  poll(function() {
   1.151 +    if (getState(key[1]) != "cancelled") {
   1.152 +      return false;
   1.153 +    }
   1.154 +    response.finish();
   1.155 +    return true;
   1.156 +  });
   1.157 +}

mercurial