Skip to content

Commit

Permalink
Fix/cmcd nor (#3747)
Browse files Browse the repository at this point in the history
* Add unit tests for Utils.js

* Use relative url for CMCD nor attribute

* URI encode the CMCD nor url
  • Loading branch information
dsilhavy committed Sep 2, 2021
1 parent 734b4af commit 73e60d5
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 8 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 37 additions & 1 deletion src/core/Utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
* @ignore
*/

import path from 'path-browserify'

class Utils {
static mixin(dest, source, copy) {
let s;
Expand Down Expand Up @@ -96,7 +98,7 @@ class Utils {
}
}

static parseHttpHeaders (headerStr) {
static parseHttpHeaders(headerStr) {
let headers = {};
if (!headerStr) {
return headers;
Expand Down Expand Up @@ -139,6 +141,40 @@ class Utils {
}
return hash;
}

/**
* Compares both urls and returns a relative url (target relative to original)
* @param {string} original
* @param {string} target
* @return {string|*}
*/
static getRelativeUrl(originalUrl, targetUrl) {
try {
const original = new URL(originalUrl);
const target = new URL(targetUrl);

// Unify the protocol to compare the origins
original.protocol = target.protocol;
if (original.origin !== target.origin) {
return targetUrl;
}

// Use the relative path implementation of the path library. We need to cut off the actual filename in the end to get the relative path
let relativePath = path.relative(original.pathname.substr(0, original.pathname.lastIndexOf('/')), target.pathname.substr(0, target.pathname.lastIndexOf('/')));

// In case the relative path is empty (both path are equal) return the filename only. Otherwise add a slash in front of the filename
const startIndexOffset = relativePath.length === 0 ? 1 : 0;
relativePath += target.pathname.substr(target.pathname.lastIndexOf('/') + startIndexOffset, target.pathname.length - 1);

// Build the other candidate, e.g. the 'host relative' path that starts with "/", and return the shortest of the two candidates.
if (target.pathname.length < relativePath.length) {
return target.pathname;
}
return relativePath;
} catch (e) {
return targetUrl
}
}
}

export default Utils;
3 changes: 1 addition & 2 deletions src/streaming/models/CmcdModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -270,8 +270,7 @@ function CmcdModel() {

if (nextRequest) {
if (request.url !== nextRequest.url) {
let url = new URL(nextRequest.url);
data.nor = url.pathname;
data.nor = encodeURIComponent(Utils.getRelativeUrl(request.url, nextRequest.url));
} else if (nextRequest.range) {
data.nrr = nextRequest.range;
}
Expand Down
90 changes: 90 additions & 0 deletions test/unit/core.Utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import Utils from '../../src/core/Utils'
import {expect} from 'chai';

describe('Utils', () => {
describe('getRelativeUrl', () => {

it('Should return complete url if no original url is given', () => {
const b = 'https://localhost:3000/d/e/f.mp4';

expect(Utils.getRelativeUrl(undefined,b)).to.be.equal('https://localhost:3000/d/e/f.mp4');
})

it('Should return relative url if strings are different after server name', () => {
const a = 'https://localhost:3000/a/b/c.mp4';
const b = 'https://localhost:3000/d/e/f.mp4';

expect(Utils.getRelativeUrl(a,b)).to.be.equal('/d/e/f.mp4');
})

it('Should return relative url if strings are similar up to one element before filename', () => {
const a = 'https://localhost:3000/a/b/c.mp4';
const b = 'https://localhost:3000/a/c/f.mp4';

expect(Utils.getRelativeUrl(a,b)).to.be.equal('../c/f.mp4');
})

it('Should return relative url if strings are similar up to filename', () => {
const a = 'https://localhost:3000/a/b/c.mp4';
const b = 'https://localhost:3000/a/b/f.mp4';

expect(Utils.getRelativeUrl(a,b)).to.be.equal('f.mp4');
})

it('Should return complete url if origin is different', () => {
const a = 'https://localhost:3000/a/b/c.mp4';
const b = 'https://loca:3000/a/b/f.mp4';

expect(Utils.getRelativeUrl(a,b)).to.be.equal('https://loca:3000/a/b/f.mp4');
})

it('Should return filename if origin differs in terms of SSL', () => {
const a = 'https://localhost:3000/a/b/c.mp4';
const b = 'http://localhost:3000/a/b/e.mp4';

expect(Utils.getRelativeUrl(a,b)).to.be.equal('e.mp4');
})

it('Should return relative url if part of the pathnames are not equal', () => {
const a = 'https://localhost:3000/a/b/c.mp4';
const b = 'https://localhost:3000/ab/b/f.mp4';

expect(Utils.getRelativeUrl(a,b)).to.be.equal('/ab/b/f.mp4');
})

it('Should return relative url if target pathname is longer than source pathname ', () => {
const a = 'https://localhost:3000/a/b/f.mp4';
const b = 'https://localhost:3000/a/b/f/e/c.mp4';

expect(Utils.getRelativeUrl(a,b)).to.be.equal('f/e/c.mp4');
})

it('Should return relative url if source pathname is longer than target pathname ', () => {
const a = 'https://localhost:3000/a/b/f/e/c.mp4';
const b = 'https://localhost:3000/a/b/f.mp4';

expect(Utils.getRelativeUrl(a,b)).to.be.equal('/a/b/f.mp4');
})

it('Should return relative url if source contains slash in the end ', () => {
const a = 'https://localhost:3000/a/';
const b = 'https://localhost:3000/a/b.mp4';

expect(Utils.getRelativeUrl(a,b)).to.be.equal('b.mp4');
})

it('Should return relative url if source pathnames are exceptionally long ', () => {
const a = 'https://localhost:3000/a/b/c/d/e/f/g/h/1.mp4';
const b = 'https://localhost:3000/a/b/c/d/e/change/i/j/k/l/m/n/2.mp4';

expect(Utils.getRelativeUrl(a,b)).to.be.equal('../../../change/i/j/k/l/m/n/2.mp4');
})

it('Should return relative url if source contains slash in the end and multiple elements in the path', () => {
const a = 'https://localhost:3000/a/b/c/';
const b = 'https://localhost:3000/a/b/x/c.mp4';

expect(Utils.getRelativeUrl(a,b)).to.be.equal('../x/c.mp4');
})
})
})
10 changes: 6 additions & 4 deletions test/unit/streaming.models.CmcdModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ describe('CmcdModel', function () {
const MEASURED_THROUGHPUT = 8327641;
const BUFFER_LEVEL = parseInt(dashMetricsMock.getCurrentBufferLevel() * 10) * 100;
const VIDEO_OBJECT_TYPE = 'v';
const NEXT_OBJECT_URL = '/next_object';
const NEXT_OBJECT_URL = 'next_object';
const NEXT_OBJECT_RANGE = '100-500';

abrControllerMock.setTopBitrateInfo({bitrate: TOP_BITRATE});
Expand All @@ -135,7 +135,8 @@ describe('CmcdModel', function () {
mediaType: MEDIA_TYPE,
quality: 0,
mediaInfo: {bitrateList: [{bandwidth: BITRATE}]},
duration: DURATION
duration: DURATION,
url: 'http://test.url/firstRequest'
};

let headers = cmcdModel.getHeaderParameters(request);
Expand Down Expand Up @@ -430,7 +431,7 @@ describe('CmcdModel', function () {
const MEASURED_THROUGHPUT = 8327641;
const BUFFER_LEVEL = parseInt(dashMetricsMock.getCurrentBufferLevel() * 10) * 100;
const VIDEO_OBJECT_TYPE = 'v';
const NEXT_OBJECT_URL = '/next_object';
const NEXT_OBJECT_URL = 'next_object';
const NEXT_OBJECT_RANGE = '100-500';

abrControllerMock.setTopBitrateInfo({bitrate: TOP_BITRATE});
Expand All @@ -444,7 +445,8 @@ describe('CmcdModel', function () {
mediaType: MEDIA_TYPE,
quality: 0,
mediaInfo: {bitrateList: [{bandwidth: BITRATE}]},
duration: DURATION
duration: DURATION,
url: 'http://test.url/firstRequest'
};

let parameters = cmcdModel.getQueryParameter(request);
Expand Down

0 comments on commit 73e60d5

Please sign in to comment.