From acd8fc430242ade7db146900b19d691f0fc7f702 Mon Sep 17 00:00:00 2001 From: Scott Lamb Date: Mon, 8 Jan 2024 20:40:47 -0800 Subject: [PATCH] prep v0.4.7: don't require DESCRIBE Content-Type https://github.com/scottlamb/moonfire-nvr/issues/298 --- CHANGELOG.md | 4 +++ Cargo.toml | 2 +- src/client/parse.rs | 35 +++++++++++++++---- .../missing_content_type_describe.txt | 20 +++++++++++ 4 files changed, 53 insertions(+), 8 deletions(-) create mode 100644 src/client/testdata/missing_content_type_describe.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index fd52d5c..bc4458d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## `v0.4.7` (2024-01-08) + +* support servers that do not set `Content-Type` on `DESCRIBE` responses + ## `v0.4.6` (2023-12-29) * add default User-Agent header diff --git a/Cargo.toml b/Cargo.toml index f08c6da..5e110b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ default-members = ["."] [package] name = "retina" -version = "0.4.6" +version = "0.4.7" authors = ["Scott Lamb "] license = "MIT/Apache-2.0" edition = "2021" diff --git a/src/client/parse.rs b/src/client/parse.rs index eb8ab14..fb274a5 100644 --- a/src/client/parse.rs +++ b/src/client/parse.rs @@ -410,14 +410,25 @@ pub(crate) fn parse_describe( request_url: Url, response: &rtsp_types::Response, ) -> Result { - if !matches!(response.header(&rtsp_types::headers::CONTENT_TYPE), Some(v) if v.as_str() == "application/sdp") - { - return Err(format!( - "Describe response not of expected application/sdp content type: {:#?}", - &response - )); + match response.header(&rtsp_types::headers::CONTENT_TYPE) { + Some(v) if v.as_str() == "application/sdp" => {} + Some(v) => { + let mut buf = vec![]; + response.write(&mut buf).map_err(|e| e.to_string())?; + return Err(format!( + "DESCRIBE response at {} has unexpected content type {}:\n{:?}", + request_url.as_str(), + v, + MostlyAscii(&buf) + )); + } + None => { + warn!( + "DESCRIBE response at {} has no content type; trying sdp anyway", + request_url.as_str() + ); + } } - let raw_sdp = MostlyAscii(&response.body()[..]); let sdp = sdp_types::Session::parse(raw_sdp.0) .map_err(|e| format!("Unable to parse SDP: {e}\n\n{raw_sdp:#?}",))?; @@ -1179,6 +1190,16 @@ mod tests { }; } + #[test] + fn missing_contenttype_describe() { + let prefix = "rtsp://192.168.1.101/live/test"; + parse_describe( + prefix, + include_bytes!("testdata/missing_content_type_describe.txt"), + ) + .unwrap(); + } + /// Simulates a negative `rtptime` value in the `PLAY` response, as returned by the OMNY M5S2A /// 2812 in [scottlamb/moonfire-nvr#224](https://github.com/scottlamb/moonfire-nvr/issues/224). /// diff --git a/src/client/testdata/missing_content_type_describe.txt b/src/client/testdata/missing_content_type_describe.txt new file mode 100644 index 0000000..1ee5ea8 --- /dev/null +++ b/src/client/testdata/missing_content_type_describe.txt @@ -0,0 +1,20 @@ +RTSP/1.0 200 OK +CSeq: 1 +Content-Length: 494 +Session: l0TtlUFSR + +v=0 +o=- 0 0 IN IP4 127.0.0.1 +s=No Name +c=IN IP4 192.168.1.101 +t=0 0 +a=tool:libavformat 58.25.100 +m=video 0 RTP/AVP 96 +a=rtpmap:96 H264/90000 +a=fmtp:96 packetization-mode=1; sprop-parameter-sets=Z2QADazZQUGfnwEQAAADABAAAAMDwPFCmWA=,aOvjyyLA; profile-level-id=64000D +a=control:streamid=0 +m=audio 0 RTP/AVP 97 +b=AS:128 +a=rtpmap:97 MPEG4-GENERIC/48000/2 +a=fmtp:97 profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3; config=119056E500 +a=control:streamid=1