Make a mount point of "/" work correctly.

As far as I can tell, this is neither explicitly allowed nor
forbidden by RFC 7826.

Meanwhile, URLs such as rtsp://<IP>:554 or rtsp://<IP>:554/ are in
use in the wild (presumably with non-GStreamer servers).

GStreamer's prior behavior was confusing, in that
gst_rtsp_mount_points_add_factory() would appear to accept a mount
path of "" or "/", but later connection attempts would fail with a
"media not found" error.

This commit makes a mount path of "/" work for either form of URL,
while an empty mount path ("") is rejected and logs a warning.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-rtsp-server/-/merge_requests/168>
This commit is contained in:
John Lindgren 2020-11-05 16:02:49 -05:00 committed by John Lindgren
parent 9f42f941d7
commit c4762da9b7
3 changed files with 31 additions and 9 deletions

View file

@ -1320,10 +1320,12 @@ default_make_path_from_uri (GstRTSPClient * client, const GstRTSPUrl * uri)
{ {
gchar *path; gchar *path;
if (uri->query) if (uri->query) {
path = g_strconcat (uri->abspath, "?", uri->query, NULL); path = g_strconcat (uri->abspath, "?", uri->query, NULL);
else } else {
path = g_strdup (uri->abspath); /* normalize rtsp://<IP>:<PORT> to rtsp://<IP>:<PORT>/ */
path = g_strdup (uri->abspath[0] ? uri->abspath : "/");
}
return path; return path;
} }
@ -2763,9 +2765,15 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx)
} }
} else { } else {
/* path is what matched. */ /* path is what matched. */
path[matched] = '\0'; gchar *newpath = g_strndup (path, matched);
/* control is remainder */ /* control is remainder */
control = &path[matched + 1]; if (matched == 1 && path[0] == '/')
control = g_strdup (&path[1]);
else
control = g_strdup (&path[matched + 1]);
g_free (path);
path = newpath;
/* find the stream now using the control part */ /* find the stream now using the control part */
stream = gst_rtsp_media_find_stream (media, control); stream = gst_rtsp_media_find_stream (media, control);
@ -2977,6 +2985,7 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx)
g_object_unref (media); g_object_unref (media);
g_object_unref (session); g_object_unref (session);
g_free (path); g_free (path);
g_free (control);
return TRUE; return TRUE;
@ -3109,6 +3118,7 @@ keymgmt_error:
g_object_unref (session); g_object_unref (session);
cleanup_path: cleanup_path:
g_free (path); g_free (path);
g_free (control);
return FALSE; return FALSE;
} }
} }

View file

@ -171,7 +171,8 @@ gst_rtsp_mount_points_new (void)
static gchar * static gchar *
default_make_path (GstRTSPMountPoints * mounts, const GstRTSPUrl * url) default_make_path (GstRTSPMountPoints * mounts, const GstRTSPUrl * url)
{ {
return g_strdup (url->abspath); /* normalize rtsp://<IP>:<PORT> to rtsp://<IP>:<PORT>/ */
return g_strdup (url->abspath[0] ? url->abspath : "/");
} }
/** /**
@ -210,6 +211,10 @@ has_prefix (DataItem * str, DataItem * prefix)
if (str->len < prefix->len) if (str->len < prefix->len)
return FALSE; return FALSE;
/* special case when "/" is the entire prefix */
if (prefix->len == 1 && prefix->path[0] == '/' && str->path[0] == '/')
return TRUE;
/* if str is larger, it there should be a / following the prefix */ /* if str is larger, it there should be a / following the prefix */
if (str->len > prefix->len && str->path[prefix->len] != '/') if (str->len > prefix->len && str->path[prefix->len] != '/')
return FALSE; return FALSE;
@ -331,7 +336,8 @@ gst_rtsp_mount_points_remove_factory_unlocked (GstRTSPMountPoints * mounts,
* *
* Attach @factory to the mount point @path in @mounts. * Attach @factory to the mount point @path in @mounts.
* *
* @path is of the form (/node)+. Any previous mount point will be freed. * @path is either of the form (/node)+ or the root path '/'. (An empty path is
* not allowed.) Any previous mount point will be freed.
* *
* Ownership is taken of the reference on @factory so that @factory should not be * Ownership is taken of the reference on @factory so that @factory should not be
* used after calling this function. * used after calling this function.
@ -345,7 +351,7 @@ gst_rtsp_mount_points_add_factory (GstRTSPMountPoints * mounts,
g_return_if_fail (GST_IS_RTSP_MOUNT_POINTS (mounts)); g_return_if_fail (GST_IS_RTSP_MOUNT_POINTS (mounts));
g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory)); g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
g_return_if_fail (path != NULL); g_return_if_fail (path != NULL && path[0] == '/');
priv = mounts->priv; priv = mounts->priv;
@ -374,7 +380,7 @@ gst_rtsp_mount_points_remove_factory (GstRTSPMountPoints * mounts,
GstRTSPMountPointsPrivate *priv; GstRTSPMountPointsPrivate *priv;
g_return_if_fail (GST_IS_RTSP_MOUNT_POINTS (mounts)); g_return_if_fail (GST_IS_RTSP_MOUNT_POINTS (mounts));
g_return_if_fail (path != NULL); g_return_if_fail (path != NULL && path[0] == '/');
priv = mounts->priv; priv = mounts->priv;

View file

@ -194,6 +194,12 @@ gst_rtsp_session_media_matches (GstRTSPSessionMedia * media,
if (len < priv->path_len) if (len < priv->path_len)
return FALSE; return FALSE;
/* special case when "/" is the entire path */
if (priv->path_len == 1 && priv->path[0] == '/' && path[0] == '/') {
*matched = 1;
return TRUE;
}
/* if media path is larger, it there should be a / following the path */ /* if media path is larger, it there should be a / following the path */
if (len > priv->path_len && path[priv->path_len] != '/') if (len > priv->path_len && path[priv->path_len] != '/')
return FALSE; return FALSE;