Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
16 changes: 13 additions & 3 deletions src/RTCSession/ReferSubscriber.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,19 @@ module.exports = class ReferSubscriber extends EventEmitter {
let replaces = null;

if (options.replaces) {
replaces = options.replaces._request.call_id;
replaces += `;to-tag=${options.replaces._to_tag}`;
replaces += `;from-tag=${options.replaces._from_tag}`;
const dialog = options.replaces._dialog;

// RFC 3891 section 3: to-tag is the remote tag and from-tag the local
// tag of the dialog to replace, whoever sent the initial INVITE.
if (dialog) {
replaces = dialog.id.call_id;
replaces += `;to-tag=${dialog.id.remote_tag}`;
replaces += `;from-tag=${dialog.id.local_tag}`;
} else {
replaces = options.replaces._request.call_id;
replaces += `;to-tag=${options.replaces._to_tag}`;
replaces += `;from-tag=${options.replaces._from_tag}`;
}

replaces = encodeURIComponent(replaces);
}
Expand Down
71 changes: 71 additions & 0 deletions src/test/test-ReferSubscriber.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import './include/common';

// eslint-disable-next-line @typescript-eslint/no-require-imports
const ReferSubscriber = require('../RTCSession/ReferSubscriber.js');

const TARGET = 'sip:[email protected]';
const CALL_ID = 'a84b4c76e66710';
const LOCAL_TAG = 'localtag';
const REMOTE_TAG = 'remotetag';

// Session to replace, with the fields set by RTCSession once its dialog is
// confirmed.
function createReplacedSession(direction: 'outgoing' | 'incoming'): object {
const outgoing = direction === 'outgoing';

return {
_request: { call_id: CALL_ID },
// Tags of the From and To header fields of the initial INVITE.
_from_tag: outgoing ? LOCAL_TAG : REMOTE_TAG,
_to_tag: outgoing ? REMOTE_TAG : LOCAL_TAG,
_dialog: {
id: { call_id: CALL_ID, local_tag: LOCAL_TAG, remote_tag: REMOTE_TAG },
},
};
}

// Sends a REFER that replaces the given session and returns its Refer-To
// header field.
function sendRefer(replaces: object): string | undefined {
let extraHeaders: string[] = [];

const session = {
contact: '<sip:[email protected];transport=ws>',
_ua: {
_configuration: {
uri: { scheme: 'sip', user: 'alice', host: 'example.com' },
},
},
sendRequest(_method: string, options: { extraHeaders: string[] }) {
extraHeaders = options.extraHeaders;

return { cseq: 1 };
},
};

new ReferSubscriber(session).sendRefer(TARGET, { replaces });

return extraHeaders.find(header => header.startsWith('Refer-To:'));
}

describe('ReferSubscriber', () => {
test('Replaces of an outgoing session', () => {
expect(sendRefer(createReplacedSession('outgoing'))).toBe(
'Refer-To: <sip:[email protected]?Replaces=a84b4c76e66710%3Bto-tag%3Dremotetag%3Bfrom-tag%3Dlocaltag>'
);
});

test('Replaces of an incoming session', () => {
expect(sendRefer(createReplacedSession('incoming'))).toBe(
'Refer-To: <sip:[email protected]?Replaces=a84b4c76e66710%3Bto-tag%3Dremotetag%3Bfrom-tag%3Dlocaltag>'
);
});

test('Replaces of a session without dialog', () => {
const replaces = { ...createReplacedSession('outgoing'), _dialog: null };

expect(sendRefer(replaces)).toBe(
'Refer-To: <sip:[email protected]?Replaces=a84b4c76e66710%3Bto-tag%3Dremotetag%3Bfrom-tag%3Dlocaltag>'
);
});
});