summaryrefslogtreecommitdiffstats
path: root/dom/media/test/dash_detect_stream_switch.sjs
blob: b8480a12744b0321081484804fe75162934d8fe6 (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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/* -*- Mode: JavaScript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/* dash_detect_stream_switch.sjs
 *
 * Parses requests for DASH manifests and ensures stream switching takes place
 * by verifying the subsegments downloaded and the streams they belong to.
 * If unexpected subsegments (byte ranges) are requested, the script will
 * will respond with a 404.
 */

var DEBUG = false;

function parseQuery(request, key) {
  var params = request.queryString.split("&");
  if (DEBUG) {
    dump('DASH-SJS: request params = "' + params + '"\n');
  }
  for (var j = 0; j < params.length; ++j) {
    var p = params[j];
    if (p == key) {
      return true;
    }
    if (p.indexOf(key + "=") === 0) {
      return p.substring(key.length + 1);
    }
    if (!p.includes("=") && key === "") {
      return p;
    }
  }
  return false;
}

function handleRequest(request, response) {
  try {
    var name = parseQuery(request, "name");
    var range = request.hasHeader("Range")
      ? request.getHeader("Range")
      : undefined;

    // Should not get request for 1st subsegment from 2nd stream, nor 2nd
    // subsegment from 1st stream.
    if (
      (name == "dash-webm-video-320x180.webm" &&
        range == "bytes=25514-32767") ||
      (name == "dash-webm-video-428x240.webm" && range == "bytes=228-35852")
    ) {
      throw new Error(
        "Should not request " + name + " with byte-range " + range
      );
    } else {
      var rangeSplit = range.split("=");
      if (rangeSplit.length != 2) {
        throw new Error(
          "DASH-SJS: ERROR: invalid number of tokens (" +
            rangeSplit.length +
            ") delimited by '=' in 'Range' header."
        );
      }
      var offsets = rangeSplit[1].split("-");
      if (offsets.length != 2) {
        throw new Error(
          "DASH-SJS: ERROR: invalid number of tokens (" +
            offsets.length +
            ") delimited by '-' in 'Range' header."
        );
      }
      var startOffset = parseInt(offsets[0]);
      var endOffset = parseInt(offsets[1]);
      var file = Services.dirsvc.get("CurWorkD", Ci.nsIFile);
      var fis = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(
        Ci.nsIFileInputStream
      );
      var bis = Cc["@mozilla.org/binaryinputstream;1"].createInstance(
        Ci.nsIBinaryInputStream
      );

      var paths = "tests/dom/media/test/" + name;
      var split = paths.split("/");
      for (var i = 0; i < split.length; ++i) {
        file.append(split[i]);
      }

      fis.init(file, -1, -1, false);
      // Exception: start offset should be within file bounds.
      if (startOffset > file.fileSize) {
        throw new Error(
          "Starting offset [" +
            startOffset +
            "] is after end of file [" +
            file.fileSize +
            "]."
        );
      }
      // End offset may be too large in the MPD. Real world HTTP servers just
      // return what data they can; do the same here - reduce the end offset.
      if (endOffset >= file.fileSize) {
        if (DEBUG) {
          dump(
            "DASH-SJS: reducing endOffset [" +
              endOffset +
              "] to fileSize [" +
              (file.fileSize - 1) +
              "]\n"
          );
        }
        endOffset = file.fileSize - 1;
      }
      fis.seek(Ci.nsISeekableStream.NS_SEEK_SET, startOffset);
      bis.setInputStream(fis);

      var byteLengthToRead = endOffset + 1 - startOffset;
      var totalBytesExpected = byteLengthToRead + startOffset;
      if (DEBUG) {
        dump(
          "DASH-SJS: byteLengthToRead = " +
            byteLengthToRead +
            " byteLengthToRead+startOffset = " +
            totalBytesExpected +
            " fileSize = " +
            file.fileSize +
            "\n"
        );
      }

      var bytes = bis.readBytes(byteLengthToRead);
      response.setStatusLine(request.httpVersion, 206, "Partial Content");
      response.setHeader("Content-Length", "" + bytes.length, false);
      response.setHeader("Content-Type", "application/dash+xml", false);
      var contentRange =
        "bytes " + startOffset + "-" + endOffset + "/" + file.fileSize;
      response.setHeader("Content-Range", contentRange, false);
      response.write(bytes, bytes.length);
      bis.close();
    }
  } catch (e) {
    dump("DASH-SJS-ERROR: " + e + "\n");
    response.setStatusLine(request.httpVersion, 404, "Not found");
  }
}