tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

dash_detect_stream_switch.sjs (4700B)


      1 /* -*- Mode: JavaScript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4  * License, v. 2.0. If a copy of the MPL was not distributed with this
      5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 /* dash_detect_stream_switch.sjs
      8  *
      9  * Parses requests for DASH manifests and ensures stream switching takes place
     10  * by verifying the subsegments downloaded and the streams they belong to.
     11  * If unexpected subsegments (byte ranges) are requested, the script will
     12  * will respond with a 404.
     13  */
     14 
     15 var DEBUG = false;
     16 
     17 function parseQuery(request, key) {
     18   var params = request.queryString.split("&");
     19   if (DEBUG) {
     20     dump('DASH-SJS: request params = "' + params + '"\n');
     21   }
     22   for (var j = 0; j < params.length; ++j) {
     23     var p = params[j];
     24     if (p == key) {
     25       return true;
     26     }
     27     if (p.indexOf(key + "=") === 0) {
     28       return p.substring(key.length + 1);
     29     }
     30     if (!p.includes("=") && key === "") {
     31       return p;
     32     }
     33   }
     34   return false;
     35 }
     36 
     37 function handleRequest(request, response) {
     38   try {
     39     var name = parseQuery(request, "name");
     40     var range = request.hasHeader("Range")
     41       ? request.getHeader("Range")
     42       : undefined;
     43 
     44     // Should not get request for 1st subsegment from 2nd stream, nor 2nd
     45     // subsegment from 1st stream.
     46     if (
     47       (name == "dash-webm-video-320x180.webm" &&
     48         range == "bytes=25514-32767") ||
     49       (name == "dash-webm-video-428x240.webm" && range == "bytes=228-35852")
     50     ) {
     51       throw new Error(
     52         "Should not request " + name + " with byte-range " + range
     53       );
     54     } else {
     55       var rangeSplit = range.split("=");
     56       if (rangeSplit.length != 2) {
     57         throw new Error(
     58           "DASH-SJS: ERROR: invalid number of tokens (" +
     59             rangeSplit.length +
     60             ") delimited by '=' in 'Range' header."
     61         );
     62       }
     63       var offsets = rangeSplit[1].split("-");
     64       if (offsets.length != 2) {
     65         throw new Error(
     66           "DASH-SJS: ERROR: invalid number of tokens (" +
     67             offsets.length +
     68             ") delimited by '-' in 'Range' header."
     69         );
     70       }
     71       var startOffset = parseInt(offsets[0]);
     72       var endOffset = parseInt(offsets[1]);
     73       var file = Services.dirsvc.get("CurWorkD", Ci.nsIFile);
     74       var fis = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(
     75         Ci.nsIFileInputStream
     76       );
     77       var bis = Cc["@mozilla.org/binaryinputstream;1"].createInstance(
     78         Ci.nsIBinaryInputStream
     79       );
     80 
     81       var paths = "tests/dom/media/test/" + name;
     82       var split = paths.split("/");
     83       for (var i = 0; i < split.length; ++i) {
     84         file.append(split[i]);
     85       }
     86 
     87       fis.init(file, -1, -1, false);
     88       // Exception: start offset should be within file bounds.
     89       if (startOffset > file.fileSize) {
     90         throw new Error(
     91           "Starting offset [" +
     92             startOffset +
     93             "] is after end of file [" +
     94             file.fileSize +
     95             "]."
     96         );
     97       }
     98       // End offset may be too large in the MPD. Real world HTTP servers just
     99       // return what data they can; do the same here - reduce the end offset.
    100       if (endOffset >= file.fileSize) {
    101         if (DEBUG) {
    102           dump(
    103             "DASH-SJS: reducing endOffset [" +
    104               endOffset +
    105               "] to fileSize [" +
    106               (file.fileSize - 1) +
    107               "]\n"
    108           );
    109         }
    110         endOffset = file.fileSize - 1;
    111       }
    112       fis.seek(Ci.nsISeekableStream.NS_SEEK_SET, startOffset);
    113       bis.setInputStream(fis);
    114 
    115       var byteLengthToRead = endOffset + 1 - startOffset;
    116       var totalBytesExpected = byteLengthToRead + startOffset;
    117       if (DEBUG) {
    118         dump(
    119           "DASH-SJS: byteLengthToRead = " +
    120             byteLengthToRead +
    121             " byteLengthToRead+startOffset = " +
    122             totalBytesExpected +
    123             " fileSize = " +
    124             file.fileSize +
    125             "\n"
    126         );
    127       }
    128 
    129       var bytes = bis.readBytes(byteLengthToRead);
    130       response.setStatusLine(request.httpVersion, 206, "Partial Content");
    131       response.setHeader("Content-Length", "" + bytes.length, false);
    132       response.setHeader("Content-Type", "application/dash+xml", false);
    133       var contentRange =
    134         "bytes " + startOffset + "-" + endOffset + "/" + file.fileSize;
    135       response.setHeader("Content-Range", contentRange, false);
    136       response.write(bytes, bytes.length);
    137       bis.close();
    138     }
    139   } catch (e) {
    140     dump("DASH-SJS-ERROR: " + e + "\n");
    141     response.setStatusLine(request.httpVersion, 404, "Not found");
    142   }
    143 }