Skip to content

Commit

Permalink
Add option to follow 301 and 302
Browse files Browse the repository at this point in the history
  • Loading branch information
yujincheng08 committed Feb 15, 2024
1 parent acd8fc4 commit 8ffe41c
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 3 deletions.
54 changes: 51 additions & 3 deletions src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -497,14 +497,15 @@ fn keepalive_interval(session: &SessionHeader) -> std::time::Duration {
/// Options which must be known right as a session is created.
///
/// Decisions which can be deferred are in [`SetupOptions`] or [`PlayOptions`] instead.
#[derive(Default)]
#[derive(Default, Clone)]
pub struct SessionOptions {
creds: Option<Credentials>,
user_agent: Option<Box<str>>,
session_group: Option<Arc<SessionGroup>>,
teardown: TeardownPolicy,
unassigned_channel_data: UnassignedChannelDataPolicy,
session_id: SessionIdPolicy,
max_redirect: u8,
}

/// Policy for handling data received on unassigned RTSP interleaved channels.
Expand Down Expand Up @@ -713,6 +714,11 @@ impl SessionOptions {
self.session_id = policy;
self
}

pub fn max_redirect(mut self, max_redirect: u8) -> Self {
self.max_redirect = max_redirect;
self
}
}

/// Per-stream options decided for `SETUP` time, for future expansion.
Expand Down Expand Up @@ -1352,6 +1358,33 @@ impl RtspConnection {
}),
};
continue;
} else if resp.status() == rtsp_types::StatusCode::Found
|| resp.status() == rtsp_types::StatusCode::MovedPermanently
{
let location = match resp.header(&rtsp_types::headers::LOCATION) {
None => bail!(ErrorInt::RtspResponseError {
conn_ctx: *self.inner.ctx(),
msg_ctx,
method: req.method().clone(),
cseq,
status: resp.status(),
description: "Redirect without Location header".into(),
}),
Some(h) => h,
};
let location = location.as_str();
let location = match location.parse() {
Ok(l) => l,
Err(e) => bail!(ErrorInt::RtspResponseError {
conn_ctx: *self.inner.ctx(),
msg_ctx,
method: req.method().clone(),
cseq,
status: resp.status(),
description: format!("Can't parse Location header: {e}"),
}),
};
bail!(ErrorInt::RtspRedirection(location));
} else if !resp.status().is_success() {
bail!(ErrorInt::RtspResponseError {
conn_ctx: *self.inner.ctx(),
Expand Down Expand Up @@ -1487,8 +1520,23 @@ impl Session<Described> {
///
/// Expects to be called from a tokio runtime.
pub async fn describe(url: Url, options: SessionOptions) -> Result<Self, Error> {
let conn = RtspConnection::connect(&url).await?;
Self::describe_with_conn(conn, options, url).await
let mut url = url;
let mut redirect = 0u8;
loop {
let conn = RtspConnection::connect(&url).await?;
let result = Self::describe_with_conn(conn, options.clone(), url).await;
if let Err(Error(e)) = &result {
if let ErrorInt::RtspRedirection(ref location) = e.as_ref() {
if options.max_redirect > redirect {
redirect += 1;
url = location.clone();
continue;
}
bail!(ErrorInt::RtspTooManyRedirects);
}
}
return result;
}
}

async fn describe_with_conn(
Expand Down
7 changes: 7 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::{fmt::Display, sync::Arc};
use crate::{ConnectionContext, PacketContext, RtspMessageContext, StreamContext, WallTime};
use bytes::Bytes;
use thiserror::Error;
use url::Url;

/// An opaque `std::error::Error + Send + Sync + 'static` implementation.
///
Expand Down Expand Up @@ -49,6 +50,12 @@ pub(crate) enum ErrorInt {
#[error("Invalid argument: {0}")]
InvalidArgument(String),

#[error("Redirect to: {0}")]
RtspRedirection(Url),

#[error("Too many redirects")]
RtspTooManyRedirects,

/// Unparseable or unexpected RTSP message.
#[error("RTSP framing error: {description}\n\nconn: {conn_ctx}\nmsg: {msg_ctx}")]
RtspFramingError {
Expand Down

0 comments on commit 8ffe41c

Please sign in to comment.