1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/media/test/dash_detect_stream_switch.sjs Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,114 @@ 1.4 +/* -*- Mode: JavaScript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* dash_detect_stream_switch.sjs 1.11 + * 1.12 + * Parses requests for DASH manifests and ensures stream switching takes place 1.13 + * by verifying the subsegments downloaded and the streams they belong to. 1.14 + * If unexpected subsegments (byte ranges) are requested, the script will 1.15 + * will respond with a 404. 1.16 + */ 1.17 + 1.18 +var DEBUG = false; 1.19 + 1.20 +function parseQuery(request, key) { 1.21 + var params = request.queryString.split('&'); 1.22 + if (DEBUG) { 1.23 + dump("DASH-SJS: request params = \"" + params + "\"\n"); 1.24 + } 1.25 + for (var j = 0; j < params.length; ++j) { 1.26 + var p = params[j]; 1.27 + if (p == key) 1.28 + return true; 1.29 + if (p.indexOf(key + "=") === 0) 1.30 + return p.substring(key.length + 1); 1.31 + if (p.indexOf("=") < 0 && key === "") 1.32 + return p; 1.33 + } 1.34 + return false; 1.35 +} 1.36 + 1.37 +function handleRequest(request, response) 1.38 +{ 1.39 + try { 1.40 + var name = parseQuery(request, "name"); 1.41 + var range = request.hasHeader("Range") ? request.getHeader("Range") 1.42 + : undefined; 1.43 + 1.44 + // Should not get request for 1st subsegment from 2nd stream, nor 2nd 1.45 + // subsegment from 1st stream. 1.46 + if (name == "dash-webm-video-320x180.webm" && range == "bytes=25514-32767" || 1.47 + name == "dash-webm-video-428x240.webm" && range == "bytes=228-35852") 1.48 + { 1.49 + throw "Should not request " + name + " with byte-range " + range; 1.50 + } else { 1.51 + var rangeSplit = range.split("="); 1.52 + if (rangeSplit.length != 2) { 1.53 + throw "DASH-SJS: ERROR: invalid number of tokens (" + rangeSplit.length + 1.54 + ") delimited by \'=\' in \'Range\' header."; 1.55 + } 1.56 + var offsets = rangeSplit[1].split("-"); 1.57 + if (offsets.length != 2) { 1.58 + throw "DASH-SJS: ERROR: invalid number of tokens (" + offsets.length + 1.59 + ") delimited by \'-\' in \'Range\' header."; 1.60 + } 1.61 + var startOffset = parseInt(offsets[0]); 1.62 + var endOffset = parseInt(offsets[1]); 1.63 + var file = Components.classes["@mozilla.org/file/directory_service;1"]. 1.64 + getService(Components.interfaces.nsIProperties). 1.65 + get("CurWorkD", Components.interfaces.nsILocalFile); 1.66 + var fis = Components.classes['@mozilla.org/network/file-input-stream;1']. 1.67 + createInstance(Components.interfaces.nsIFileInputStream); 1.68 + var bis = Components.classes["@mozilla.org/binaryinputstream;1"]. 1.69 + createInstance(Components.interfaces.nsIBinaryInputStream); 1.70 + 1.71 + var paths = "tests/content/media/test/" + name; 1.72 + var split = paths.split("/"); 1.73 + for (var i = 0; i < split.length; ++i) { 1.74 + file.append(split[i]); 1.75 + } 1.76 + 1.77 + fis.init(file, -1, -1, false); 1.78 + // Exception: start offset should be within file bounds. 1.79 + if (startOffset > file.fileSize) { 1.80 + throw "Starting offset [" + startOffset + "] is after end of file [" + 1.81 + file.fileSize + "]."; 1.82 + } 1.83 + // End offset may be too large in the MPD. Real world HTTP servers just 1.84 + // return what data they can; do the same here - reduce the end offset. 1.85 + if (endOffset >= file.fileSize) { 1.86 + if (DEBUG) { 1.87 + dump("DASH-SJS: reducing endOffset [" + endOffset + "] to fileSize [" + 1.88 + (file.fileSize-1) + "]\n"); 1.89 + } 1.90 + endOffset = file.fileSize-1; 1.91 + } 1.92 + fis.seek(Components.interfaces.nsISeekableStream.NS_SEEK_SET, startOffset); 1.93 + bis.setInputStream(fis); 1.94 + 1.95 + var byteLengthToRead = endOffset + 1 - startOffset; 1.96 + var totalBytesExpected = byteLengthToRead + startOffset; 1.97 + if (DEBUG) { 1.98 + dump("DASH-SJS: byteLengthToRead = " + byteLengthToRead + 1.99 + " byteLengthToRead+startOffset = " + totalBytesExpected + 1.100 + " fileSize = " + file.fileSize + "\n"); 1.101 + } 1.102 + 1.103 + var bytes = bis.readBytes(byteLengthToRead); 1.104 + response.setStatusLine(request.httpVersion, 206, "Partial Content"); 1.105 + response.setHeader("Content-Length", ""+bytes.length, false); 1.106 + response.setHeader("Content-Type", "application/dash+xml", false); 1.107 + var contentRange = "bytes " + startOffset + "-" + endOffset + "/" + 1.108 + file.fileSize; 1.109 + response.setHeader("Content-Range", contentRange, false); 1.110 + response.write(bytes, bytes.length); 1.111 + bis.close(); 1.112 + } 1.113 + } catch (e) { 1.114 + dump ("DASH-SJS-ERROR: " + e + "\n"); 1.115 + response.setStatusLine(request.httpVersion, 404, "Not found"); 1.116 + } 1.117 +}