Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RecorderEndpoint: Parse and use username/password from URLs #44

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 0 additions & 14 deletions server/module-core/src/gst-plugins/commons/kmsutils.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,20 +55,6 @@ kms_utils_debug_graph_delay (GstBin * bin, guint interval)
g_timeout_add_seconds (interval, debug_graph, bin);
}

gboolean
kms_is_valid_uri (const gchar * url)
{
gboolean ret;
GRegex *regex;

regex = g_regex_new ("^(?:((?:https?):)\\/\\/)([^:\\/\\s]+)(?::(\\d*))?(?:\\/"
"([^\\s?#]+)?([?][^?#]*)?(#.*)?)?$", 0, 0, NULL);
ret = g_regex_match (regex, url, G_REGEX_MATCH_ANCHORED, NULL);
g_regex_unref (regex);

return ret;
}

gboolean
gst_element_sync_state_with_parent_target_state (GstElement * element)
{
Expand Down
1 change: 0 additions & 1 deletion server/module-core/src/gst-plugins/commons/kmsutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ gboolean kms_element_for_each_sink_pad (GstElement * element,
KmsPadCallback action, gpointer data);

void kms_utils_debug_graph_delay (GstBin * bin, guint interval);
gboolean kms_is_valid_uri (const gchar * url);

gboolean gst_element_sync_state_with_parent_target_state (GstElement * element);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,10 @@ Both username and password fields should be provided in URL-encoded form:

rtsp://us%3Aer:p%40ssword@example.com/test.mp4?user=token/s3/request&uri=umsp://example.com:1234/

GStreamer will use `:` and `@` to break the string, and perform URL-decoding on
the resulting fields.
GStreamer's `rtspsrc` uses the function `gst_rtsp_url_parse()` to break the string at the points
where `@` and `:` delimit username and password fields, then performs URL-decoding on those fields.

See: https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/blob/1.16/gst-libs/gst/rtsp/gstrtspurl.c#L101
*/

void UriEndpointImpl::checkUri ()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,35 +122,77 @@ kms_base_media_muxer_dot_file_impl (KmsBaseMediaMuxer * obj)
}

static GstElement *
kms_base_media_muxer_get_sink_fallback (KmsBaseMediaMuxer * self,
const gchar * uri)
kms_base_media_muxer_get_sink_fallback (KmsBaseMediaMuxer *self,
const gchar *uri)
{
GstElement *sink = NULL;
gchar *prot;

prot = gst_uri_get_protocol (uri);

if ((g_strcmp0 (prot, HTTP_PROTO) == 0)
|| (g_strcmp0 (prot, HTTPS_PROTO) == 0)) {

if (kms_is_valid_uri (uri)) {
/* We use the GStreamer CURL plugin */
sink = kms_utils_element_factory_make ("curlhttpsink", OBJECT_NAME);
if (sink != NULL) {
g_object_set (sink, "blocksize", MEGA_BYTES (1), "qos", FALSE,
"async", FALSE, NULL);
}
else {
GST_ERROR_OBJECT (self, "CURL HTTP plugin not available: curlhttpsink");
}
} else {
GST_ERROR_OBJECT (self, "URL not valid");
}

#if GST_CHECK_VERSION(1, 18, 0)
// Starting from GStreamer 1.18, this function will be able to support
// special characters in username/password URL-encoded fields.
GstUri *gst_uri = gst_uri_from_string_escaped (uri);
#else
GstUri *gst_uri = gst_uri_from_string (uri);
#endif

if (gst_uri == NULL) {
GST_ERROR_OBJECT (self, "URL is not valid: parsing failed");
goto finish;
}

const gchar *proto = gst_uri_get_scheme (gst_uri);
if ((g_strcmp0 (proto, HTTP_PROTO) != 0)
&& (g_strcmp0 (proto, HTTPS_PROTO) != 0)) {
// Other schemes are not supported here.
goto finish;
}

// We use the GStreamer cURL plugin.
sink = kms_utils_element_factory_make ("curlhttpsink", OBJECT_NAME);
if (sink == NULL) {
GST_ERROR_OBJECT (self, "cURL plugin not available: curlhttpsink");
goto finish;
}

g_object_set (sink, "blocksize", MEGA_BYTES (1), "qos", FALSE, "async", FALSE,
NULL);

// Extract and set username and password, if any.
const gchar *userinfo = gst_uri_get_userinfo (gst_uri);
if (userinfo == NULL) {
GST_DEBUG_OBJECT (self,
"'username:password' field is empty, nothing to parse");
goto finish;
}

gchar *colon = strchr (userinfo, ':');
if (colon == NULL) {
GST_ERROR_OBJECT (self,
"'username:password' field is not valid: parsing failed");
goto finish;
}

{
gchar *username = g_uri_unescape_segment (userinfo, colon, NULL);
colon++;
gchar *password = g_uri_unescape_segment (colon, NULL, NULL);

GST_DEBUG_OBJECT (self, "'username' parsed as '%s' (password hidden)",
username);

g_object_set (sink, "user", username, "passwd", password, NULL);

g_free (username);
g_free (password);
}

g_free (prot);
finish:
#if GST_CHECK_VERSION(1, 18, 0)
gst_clear_uri (&gst_uri);
#else
g_clear_pointer (&gst_uri, gst_uri_unref);
#endif

/* Add more if required */
return sink;
}

Expand All @@ -177,8 +219,9 @@ kms_base_media_muxer_get_sink (KmsBaseMediaMuxer * self, const gchar * uri)
/* handle them. We try to find such element before failing to attend */
/* this request */
sink = kms_base_media_muxer_get_sink_fallback (self, uri);
if (sink == NULL)
if (sink == NULL) {
goto no_sink;
}
g_clear_error (&err);
}

Expand Down