Skip to content

Commit

Permalink
feat(webex-core): hostmap interceptor (webex#3789)
Browse files Browse the repository at this point in the history
  • Loading branch information
Coread authored and parv_gour committed Sep 27, 2024
1 parent 56ee8a7 commit f04a644
Show file tree
Hide file tree
Showing 7 changed files with 201 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/@webex/webex-core/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export {
Services,
ServiceHost,
ServiceUrl,
HostMapInterceptor,
} from './lib/services';

export {
Expand Down
1 change: 1 addition & 0 deletions packages/@webex/webex-core/src/lib/services/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ registerInternalPlugin('services', Services, {
export {constants};
export {default as ServiceInterceptor} from './interceptors/service';
export {default as ServerErrorInterceptor} from './interceptors/server-error';
export {default as HostMapInterceptor} from './interceptors/hostmap';
export {default as Services} from './services';
export {default as ServiceCatalog} from './service-catalog';
export {default as ServiceRegistry} from './service-registry';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*!
* Copyright (c) 2015-2024 Cisco Systems, Inc. See LICENSE file.
*/

import {Interceptor} from '@webex/http-core';

/**
* This interceptor replaces the host in the request uri with the host from the hostmap
* It will attempt to do this for every request, but not all URIs will be in the hostmap
* URIs with hosts that are not in the hostmap will be left unchanged
*/
export default class HostMapInterceptor extends Interceptor {
/**
* @returns {HostMapInterceptor}
*/
static create() {
return new HostMapInterceptor({webex: this});
}

/**
* @see Interceptor#onRequest
* @param {Object} options
* @returns {Object}
*/
onRequest(options) {
if (options.uri) {
try {
options.uri = this.webex.internal.services.replaceHostFromHostmap(options.uri);
} catch (error) {
/* empty */
}
}

return options;
}
}
27 changes: 27 additions & 0 deletions packages/@webex/webex-core/src/lib/services/services.js
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,33 @@ const Services = WebexPlugin.extend({
});
},

/**
* Looks up the hostname in the host catalog
* and replaces it with the first host if it finds it
* @param {string} uri
* @returns {string} uri with the host replaced
*/
replaceHostFromHostmap(uri) {
const url = new URL(uri);
const hostCatalog = this._hostCatalog;

if (!hostCatalog) {
return uri;
}

const host = hostCatalog[url.host];

if (host && host[0]) {
const newHost = host[0].host;

url.host = newHost;

return url.toString();
}

return uri;
},

/**
* @private
* Organize a received hostmap from a service
Expand Down
2 changes: 2 additions & 0 deletions packages/@webex/webex-core/src/webex-core.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import WebexUserAgentInterceptor from './interceptors/webex-user-agent';
import RateLimitInterceptor from './interceptors/rate-limit';
import EmbargoInterceptor from './interceptors/embargo';
import DefaultOptionsInterceptor from './interceptors/default-options';
import HostMapInterceptor from './lib/services/interceptors/hostmap';
import config from './config';
import {makeWebexStore} from './lib/storage';
import mixinWebexCorePlugins from './lib/webex-core-plugin-mixin';
Expand Down Expand Up @@ -71,6 +72,7 @@ const interceptors = {
NetworkTimingInterceptor: NetworkTimingInterceptor.create,
EmbargoInterceptor: EmbargoInterceptor.create,
DefaultOptionsInterceptor: DefaultOptionsInterceptor.create,
HostMapInterceptor: HostMapInterceptor.create,
};

const preInterceptors = [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*!
* Copyright (c) 2015-2024 Cisco Systems, Inc. See LICENSE file.
*/

/* eslint-disable camelcase */

import sinon from 'sinon';
import {assert} from '@webex/test-helper-chai';
import MockWebex from '@webex/test-helper-mock-webex';
import {HostMapInterceptor, config, Credentials} from '@webex/webex-core';
import {cloneDeep} from 'lodash';

describe('webex-core', () => {
describe('Interceptors', () => {
describe('HostMapInterceptor', () => {
let interceptor, webex;

beforeEach(() => {
webex = new MockWebex({
children: {
credentials: Credentials,
},
config: cloneDeep(config),
request: sinon.spy(),
});

webex.internal.services = {
replaceHostFromHostmap: sinon.stub().returns('http://replaceduri.com'),
}

interceptor = Reflect.apply(HostMapInterceptor.create, webex, []);
});

describe('#onRequest', () => {
it('calls replaceHostFromHostmap if options.uri is defined', () => {
const options = {
uri: 'http://example.com',
};

interceptor.onRequest(options);

sinon.assert.calledWith(
webex.internal.services.replaceHostFromHostmap,
'http://example.com'
);

assert.equal(options.uri, 'http://replaceduri.com');
});

it('does not call replaceHostFromHostmap if options.uri is not defined', () => {
const options = {};

interceptor.onRequest(options);

sinon.assert.notCalled(webex.internal.services.replaceHostFromHostmap);

assert.isUndefined(options.uri);
});

it('does not modify options.uri if replaceHostFromHostmap throws an error', () => {
const options = {
uri: 'http://example.com',
};

webex.internal.services.replaceHostFromHostmap.throws(new Error('replaceHostFromHostmap error'));

interceptor.onRequest(options);

sinon.assert.calledWith(
webex.internal.services.replaceHostFromHostmap,
'http://example.com'
);

assert.equal(options.uri, 'http://example.com');
});
});
});
});
});
55 changes: 55 additions & 0 deletions packages/@webex/webex-core/test/unit/spec/services/services.js
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,61 @@ describe('webex-core', () => {
});
});

describe('replaceHostFromHostmap', () => {
it('returns the same uri if the hostmap is not set', () => {
services._hostCatalog = null;

const uri = 'http://example.com';

assert.equal(services.replaceHostFromHostmap(uri), uri);
});

it('returns the same uri if the hostmap does not contain the host', () => {
services._hostCatalog = {
'not-example.com': [
{
host: 'example-1.com',
ttl: -1,
priority: 5,
id: '0:0:0:example',
},
],
};

const uri = 'http://example.com';

assert.equal(services.replaceHostFromHostmap(uri), uri);
});

it('returns the original uri if the hostmap has no hosts for the host', () => {

services._hostCatalog = {
'example.com': [],
};

const uri = 'http://example.com';

assert.equal(services.replaceHostFromHostmap(uri), uri);
});

it('returns the replaces the host in the uri with the host from the hostmap', () => {
services._hostCatalog = {
'example.com': [
{
host: 'example-1.com',
ttl: -1,
priority: 5,
id: '0:0:0:example',
},
],
};

const uri = 'http://example.com/somepath';

assert.equal(services.replaceHostFromHostmap(uri), 'http://example-1.com/somepath');
});
});

describe('#_formatReceivedHostmap()', () => {
let serviceHostmap;
let formattedHM;
Expand Down

0 comments on commit f04a644

Please sign in to comment.