Skip to content

Commit 882735a

Browse files
stampercaseyclaude
andcommitted
VAPI-3163 Replace Transfer SipUri with ReferSipUri in <Refer>
The Transfer SipUri carries ~12 Transfer-specific params (transfer_answer_url, uui, auth, fallback URLs) that are invalid in a REFER context. A user passing any of those would silently produce malformed BXML. ReferSipUri accepts only uri — matching the spec and the C# SDK's nested Refer.SipUri class design. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
1 parent cf272b1 commit 882735a

4 files changed

Lines changed: 54 additions & 9 deletions

File tree

bandwidth/models/bxml/verbs/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from .play_audio import PlayAudio
1313
from .record import Record
1414
from .refer import Refer
15+
from .refer_sip_uri import ReferSipUri
1516
from .redirect import Redirect
1617
from .resume_recording import ResumeRecording
1718
from .ring import Ring

bandwidth/models/bxml/verbs/refer.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66
@copyright Bandwidth INC
77
"""
88
from ..nestable_verb import NestableVerb
9-
from .sip_uri import SipUri
9+
from .refer_sip_uri import ReferSipUri
1010

1111

1212
class Refer(NestableVerb):
1313

1414
def __init__(
15-
self, sip_uri: SipUri,
15+
self, sip_uri: ReferSipUri,
1616
refer_complete_url: str=None, refer_complete_method: str=None,
1717
tag: str=None
1818
):
@@ -27,8 +27,10 @@ def __init__(
2727
handling — there is no live call to act on after success.
2828
2929
Args:
30-
sip_uri (SipUri): The SIP URI to refer the call to. Required.
31-
Exactly one <SipUri> child element is allowed.
30+
sip_uri (ReferSipUri): The SIP URI to refer the call to. Required.
31+
Exactly one <SipUri> child element is allowed. Use ReferSipUri,
32+
not SipUri — the Transfer SipUri carries callbacks and auth
33+
fields that are not valid in a REFER context.
3234
refer_complete_url (str, optional): URL to send the Refer Complete
3335
event to when the REFER flow finishes (success or failure).
3436
May be a relative URL. Defaults to None.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"""
2+
refer_sip_uri.py
3+
4+
Bandwidth's ReferSipUri BXML element
5+
6+
@copyright Bandwidth INC
7+
"""
8+
from ..verb import Verb
9+
10+
11+
class ReferSipUri(Verb):
12+
13+
def __init__(self, uri: str):
14+
"""Initialize a <SipUri> child element for use within <Refer>.
15+
16+
Unlike the SipUri used with <Transfer>, this element carries only the
17+
destination URI — no transfer callbacks, auth, or UUI headers apply
18+
to a SIP REFER.
19+
20+
Args:
21+
uri (str): The SIP URI to refer the call to (e.g. sip:user@host.example.com).
22+
"""
23+
self.uri = uri
24+
super().__init__(
25+
tag="SipUri",
26+
content=self.uri,
27+
)
28+
29+
@property
30+
def _attributes(self):
31+
return None

test/unit/models/bxml/test_refer.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,13 @@
77
"""
88
import unittest
99

10-
from bandwidth.models.bxml import Refer, SipUri, Verb, NestableVerb
10+
from bandwidth.models.bxml import Refer, ReferSipUri, SipUri, Verb, NestableVerb
1111

1212

1313
class TestRefer(unittest.TestCase):
1414

1515
def setUp(self):
16-
self.sip_uri = SipUri(
17-
uri="sip:alice@atlanta.example.com"
18-
)
16+
self.sip_uri = ReferSipUri(uri="sip:alice@atlanta.example.com")
1917
self.refer = Refer(
2018
sip_uri=self.sip_uri,
2119
refer_complete_url="https://example.com/handleRefer",
@@ -33,6 +31,19 @@ def test_to_bxml(self):
3331
assert expected == self.refer.to_bxml()
3432

3533
def test_minimal(self):
36-
minimal_refer = Refer(sip_uri=SipUri(uri="sip:bob@example.com"))
34+
minimal_refer = Refer(sip_uri=ReferSipUri(uri="sip:bob@example.com"))
3735
expected = '<Refer><SipUri>sip:bob@example.com</SipUri></Refer>'
3836
assert expected == minimal_refer.to_bxml()
37+
38+
def test_refer_sip_uri_is_not_transfer_sip_uri(self):
39+
"""ReferSipUri is a distinct type from the Transfer SipUri — no Transfer-specific
40+
attributes (transfer_answer_url, uui, auth, etc.) are accepted."""
41+
assert not isinstance(self.sip_uri, SipUri)
42+
assert isinstance(self.sip_uri, ReferSipUri)
43+
44+
def test_refer_sip_uri_has_no_transfer_attributes(self):
45+
"""ReferSipUri carries only uri — no Transfer baggage."""
46+
assert not hasattr(self.sip_uri, 'transfer_answer_url')
47+
assert not hasattr(self.sip_uri, 'uui')
48+
assert not hasattr(self.sip_uri, 'username')
49+
assert not hasattr(self.sip_uri, 'password')

0 commit comments

Comments
 (0)