use std::sync::Arc;
use rsip::{Headers, Method, Request, StatusCode};
use crate::stack::response::{build_response, ResponseBody};
use crate::stack::transaction::TransactionKey;
use crate::stack::ua::Ua;
pub struct InboundRequest {
ua: Arc<Ua>,
key: TransactionKey,
request: Request,
}
impl InboundRequest {
pub(crate) fn new(ua: Arc<Ua>, key: TransactionKey, request: Request) -> Self {
Self { ua, key, request }
}
pub fn method(&self) -> &Method {
self.request.method()
}
pub fn headers(&self) -> &Headers {
&self.request.headers
}
pub fn body(&self) -> &[u8] {
&self.request.body
}
pub fn request(&self) -> &Request {
&self.request
}
pub async fn respond(
self,
status: StatusCode,
extra_headers: Vec<rsip::Header>,
sdp: Option<Vec<u8>>,
) -> bool {
let body = sdp.map(|bytes| ResponseBody {
content_type: "application/sdp",
bytes,
});
let Some(mut response) = build_response(&self.request, status, None, None, body) else {
return false;
};
for header in extra_headers {
response.headers.push(header);
}
self.ua.answer(self.key, response).await
}
pub async fn ok(self) -> bool {
self.respond(StatusCode::OK, Vec::new(), None).await
}
}
#[cfg(test)]
mod tests {
use super::*;
use rsip::message::HeadersExt;
fn info_request() -> Request {
let raw = "INFO sip:bob@10.0.0.1:5060 SIP/2.0\r\n\
Via: SIP/2.0/UDP 1.2.3.4:5060;branch=z9hG4bK-info\r\n\
From: <sip:alice@atlanta.example.com>;tag=alice\r\n\
To: <sip:bob@biloxi.example.com>;tag=ourtag\r\n\
Call-ID: call-dlg\r\n\
CSeq: 2 INFO\r\n\
Content-Type: application/dtmf-relay\r\n\
Content-Length: 21\r\n\r\n\
Signal=5\nDuration=160";
Request::try_from(raw.as_bytes()).unwrap()
}
#[test]
fn exposes_method_headers_and_body() {
let req = info_request();
assert_eq!(*req.method(), Method::Info);
assert_eq!(req.body, b"Signal=5\nDuration=160");
assert!(req.cseq_header().is_ok());
}
}