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 }