Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(webex-core): hostmap interceptor #3789

Merged
merged 2 commits into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading