UNPKG

sip.js

Version:

A SIP library for JavaScript

87 lines (86 loc) 3.96 kB
import { InviteServerTransaction } from "../transactions/invite-server-transaction.js"; import { UserAgentServer } from "./user-agent-server.js"; /** * Re-INVITE UAS. * @remarks * 14 Modifying an Existing Session * https://tools.ietf.org/html/rfc3261#section-14 * 14.2 UAS Behavior * https://tools.ietf.org/html/rfc3261#section-14.2 * @public */ export class ReInviteUserAgentServer extends UserAgentServer { constructor(dialog, message, delegate) { super(InviteServerTransaction, dialog.userAgentCore, message, delegate); dialog.reinviteUserAgentServer = this; this.dialog = dialog; } /** * Update the dialog signaling state on a 2xx response. * @param options - Options bucket. */ accept(options = { statusCode: 200 }) { // FIXME: The next two lines SHOULD go away, but I suppose it's technically harmless... // These are here because some versions of SIP.js prior to 0.13.8 set the route set // of all in dialog ACKs based on the Record-Route headers in the associated 2xx // response. While this worked for dialog forming 2xx responses, it was technically // broken for re-INVITE ACKS as it only worked if the UAS populated the Record-Route // headers in the re-INVITE 2xx response (which is not required and a waste of bandwidth // as the should be ignored if present in re-INVITE ACKS) and the UAS populated // the Record-Route headers with the correct values (would be weird not too, but...). // Anyway, for now the technically useless Record-Route headers are being added // to maintain "backwards compatibility" with the older broken versions of SIP.js. options.extraHeaders = options.extraHeaders || []; options.extraHeaders = options.extraHeaders.concat(this.dialog.routeSet.map((route) => `Record-Route: ${route}`)); // Send and return the response const response = super.accept(options); const session = this.dialog; const result = Object.assign(Object.assign({}, response), { session }); if (options.body) { // Update dialog signaling state with offer/answer in body this.dialog.signalingStateTransition(options.body); } // Update dialog this.dialog.reConfirm(); return result; } /** * Update the dialog signaling state on a 1xx response. * @param options - Progress options bucket. */ progress(options = { statusCode: 180 }) { // Send and return the response const response = super.progress(options); const session = this.dialog; const result = Object.assign(Object.assign({}, response), { session }); // Update dialog signaling state if (options.body) { this.dialog.signalingStateTransition(options.body); } return result; } /** * TODO: Not Yet Supported * @param contacts - Contacts to redirect to. * @param options - Redirect options bucket. */ // eslint-disable-next-line @typescript-eslint/no-unused-vars redirect(contacts, options = { statusCode: 302 }) { this.dialog.signalingStateRollback(); this.dialog.reinviteUserAgentServer = undefined; // ACK will be handled by transaction throw new Error("Unimplemented."); } /** * 3.1 Background on Re-INVITE Handling by UASs * An error response to a re-INVITE has the following semantics. As * specified in Section 12.2.2 of RFC 3261 [RFC3261], if a re-INVITE is * rejected, no state changes are performed. * https://tools.ietf.org/html/rfc6141#section-3.1 * @param options - Reject options bucket. */ reject(options = { statusCode: 488 }) { this.dialog.signalingStateRollback(); this.dialog.reinviteUserAgentServer = undefined; // ACK will be handled by transaction return super.reject(options); } }