From c59ab572a5504c1bae292f7e16045980d4355e8e Mon Sep 17 00:00:00 2001 From: yeoleobun Date: Fri, 7 Nov 2025 15:01:23 +0800 Subject: [PATCH] fix accept_with_public_contact --- src/dialog/dialog.rs | 15 ++-- src/dialog/tests/test_server_dialog.rs | 94 +++++++++++++++++++++++++- 2 files changed, 98 insertions(+), 11 deletions(-) diff --git a/src/dialog/dialog.rs b/src/dialog/dialog.rs index aa58acd8..b70fc315 100644 --- a/src/dialog/dialog.rs +++ b/src/dialog/dialog.rs @@ -631,22 +631,17 @@ impl DialogInner { } } + self.local_contact + .as_ref() + .map(|c| resp_headers.push(Contact::from(c.clone()).into())); + if let Some(headers) = headers { for header in headers { resp_headers.unique_push(header); } } - resp_headers.retain(|h| { - !matches!( - h, - Header::Contact(_) | Header::ContentLength(_) | Header::UserAgent(_) - ) - }); - - self.local_contact - .as_ref() - .map(|c| resp_headers.push(Contact::from(c.clone()).into())); + resp_headers.retain(|h| !matches!(h, Header::ContentLength(_) | Header::UserAgent(_))); resp_headers.push(Header::ContentLength( body.as_ref().map_or(0u32, |b| b.len() as u32).into(), diff --git a/src/dialog/tests/test_server_dialog.rs b/src/dialog/tests/test_server_dialog.rs index 699bc60b..a974474e 100644 --- a/src/dialog/tests/test_server_dialog.rs +++ b/src/dialog/tests/test_server_dialog.rs @@ -1,13 +1,17 @@ use rsip::prelude::{HeadersExt, ToTypedHeader}; +use std::net::{IpAddr, Ipv4Addr}; +use std::sync::Arc; use tokio::sync::mpsc::unbounded_channel; use crate::{ dialog::{ dialog::DialogInner, + server_dialog::ServerInviteDialog, tests::test_dialog_states::{create_invite_request, create_test_endpoint}, DialogId, }, - transaction::key::TransactionRole, + transaction::{key::TransactionRole, transaction::TransactionEvent}, + transport::SipAddr, }; #[tokio::test] @@ -67,3 +71,91 @@ async fn test_dialog_make_request() -> crate::Result<()> { ); Ok(()) } + +#[tokio::test] +async fn test_accept_with_public_contact_preserves_contact_header() -> crate::Result<()> { + // Create dialog ID + let dialog_id = DialogId { + call_id: "test-call-id-contact".to_string(), + from_tag: "alice-tag-456".to_string(), + to_tag: "bob-tag-789".to_string(), + }; + + let endpoint = create_test_endpoint().await?; + let (tu_sender, mut tu_receiver) = unbounded_channel(); + let (state_sender, _state_receiver) = unbounded_channel(); + + // Create INVITE request + let invite_req = create_invite_request("alice-tag-456", "", "test-call-id-contact"); + + // Create server dialog inner + let dialog_inner = DialogInner::new( + TransactionRole::Server, + dialog_id.clone(), + invite_req, + endpoint.inner.clone(), + state_sender, + None, + None, + tu_sender, + ) + .expect("Failed to create dialog inner"); + + let server_dialog = ServerInviteDialog { + inner: Arc::new(dialog_inner), + }; + + // Define the public address we want to use + let public_address = Some(rsip::HostWithPort { + host: IpAddr::V4(Ipv4Addr::new(203, 0, 113, 1)).into(), + port: Some(5060.into()), + }); + + // Define local address as fallback + let local_address: SipAddr = rsip::HostWithPort::try_from("127.0.0.1:5060")?.into(); + + // Accept with public contact + server_dialog.accept_with_public_contact( + "bob", + public_address.clone(), + &local_address, + None, + None, + )?; + + // Receive the response from the transaction event channel + let event = tu_receiver + .recv() + .await + .expect("Should receive transaction event"); + + match event { + TransactionEvent::Respond(response) => { + // Verify status code is 200 OK + assert_eq!(response.status_code, rsip::StatusCode::OK); + + // Extract and verify Contact header + let contact_header = response + .contact_header() + .expect("Response should have Contact header") + .typed() + .expect("Contact header should be parseable"); + + // Verify the Contact URI matches the public address we provided + assert_eq!( + contact_header.uri.host_with_port.host, + public_address.as_ref().unwrap().host + ); + assert_eq!( + contact_header.uri.host_with_port.port, + public_address.as_ref().unwrap().port + ); + + // Verify the username in the Contact URI + assert_eq!(contact_header.uri.auth.as_ref().unwrap().user, "bob"); + } + _other => panic!("Expected TransactionEvent::Respond, got different event type"), + } + + Ok(()) +}