mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-05 05:52:37 +00:00
gst/rtsp/: Implement simple Basic Authentication support so that urls like rtsp://user:pass@hostname/rtspstream work ...
Original commit message from CVS: * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_finalize), (gst_rtspsrc_create_stream), (rtsp_auth_method_to_string), (gst_rtspsrc_parse_auth_hdr), (gst_rtspsrc_setup_auth), (gst_rtspsrc_send), (gst_rtspsrc_try_send), (gst_rtspsrc_open), (gst_rtspsrc_close), (gst_rtspsrc_play), (gst_rtspsrc_pause), (gst_rtspsrc_uri_set_uri): * gst/rtsp/gstrtspsrc.h: * gst/rtsp/rtspconnection.c: (rtsp_connection_create), (append_auth_header), (rtsp_connection_send), (rtsp_connection_free), (rtsp_connection_set_auth): * gst/rtsp/rtspconnection.h: * gst/rtsp/rtspdefs.h: * gst/rtsp/rtspurl.c: (rtsp_url_get_request_uri): * gst/rtsp/rtspurl.h: Implement simple Basic Authentication support so that urls like rtsp://user:pass@hostname/rtspstream work on hosts that require authentication.
This commit is contained in:
parent
fff672f930
commit
66df66daa2
8 changed files with 343 additions and 37 deletions
21
ChangeLog
21
ChangeLog
|
@ -1,3 +1,24 @@
|
||||||
|
2007-02-23 Jan Schmidt <thaytan@mad.scientist.com>
|
||||||
|
|
||||||
|
* gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_finalize),
|
||||||
|
(gst_rtspsrc_create_stream), (rtsp_auth_method_to_string),
|
||||||
|
(gst_rtspsrc_parse_auth_hdr), (gst_rtspsrc_setup_auth),
|
||||||
|
(gst_rtspsrc_send), (gst_rtspsrc_try_send), (gst_rtspsrc_open),
|
||||||
|
(gst_rtspsrc_close), (gst_rtspsrc_play), (gst_rtspsrc_pause),
|
||||||
|
(gst_rtspsrc_uri_set_uri):
|
||||||
|
* gst/rtsp/gstrtspsrc.h:
|
||||||
|
* gst/rtsp/rtspconnection.c: (rtsp_connection_create),
|
||||||
|
(append_auth_header), (rtsp_connection_send),
|
||||||
|
(rtsp_connection_free), (rtsp_connection_set_auth):
|
||||||
|
* gst/rtsp/rtspconnection.h:
|
||||||
|
* gst/rtsp/rtspdefs.h:
|
||||||
|
* gst/rtsp/rtspurl.c: (rtsp_url_get_request_uri):
|
||||||
|
* gst/rtsp/rtspurl.h:
|
||||||
|
|
||||||
|
Implement simple Basic Authentication support so that urls like
|
||||||
|
rtsp://user:pass@hostname/rtspstream work on hosts that require
|
||||||
|
authentication.
|
||||||
|
|
||||||
2007-02-22 Edgard Lima <edgard.lima@indt.org.br>
|
2007-02-22 Edgard Lima <edgard.lima@indt.org.br>
|
||||||
|
|
||||||
* sys/v4l2/gstv4l2object.c:
|
* sys/v4l2/gstv4l2object.c:
|
||||||
|
|
|
@ -177,6 +177,12 @@ static GstStateChangeReturn gst_rtspsrc_change_state (GstElement * element,
|
||||||
GstStateChange transition);
|
GstStateChange transition);
|
||||||
static void gst_rtspsrc_handle_message (GstBin * bin, GstMessage * message);
|
static void gst_rtspsrc_handle_message (GstBin * bin, GstMessage * message);
|
||||||
|
|
||||||
|
static gboolean gst_rtspsrc_setup_auth (GstRTSPSrc * src,
|
||||||
|
RTSPMessage * response);
|
||||||
|
static gboolean gst_rtspsrc_try_send (GstRTSPSrc * src, RTSPMessage * request,
|
||||||
|
RTSPMessage * response, RTSPStatusCode * code);
|
||||||
|
|
||||||
|
|
||||||
static gboolean gst_rtspsrc_open (GstRTSPSrc * src);
|
static gboolean gst_rtspsrc_open (GstRTSPSrc * src);
|
||||||
static gboolean gst_rtspsrc_play (GstRTSPSrc * src);
|
static gboolean gst_rtspsrc_play (GstRTSPSrc * src);
|
||||||
static gboolean gst_rtspsrc_pause (GstRTSPSrc * src);
|
static gboolean gst_rtspsrc_pause (GstRTSPSrc * src);
|
||||||
|
@ -301,6 +307,7 @@ gst_rtspsrc_finalize (GObject * object)
|
||||||
g_free (rtspsrc->stream_rec_lock);
|
g_free (rtspsrc->stream_rec_lock);
|
||||||
g_cond_free (rtspsrc->loop_cond);
|
g_cond_free (rtspsrc->loop_cond);
|
||||||
g_free (rtspsrc->location);
|
g_free (rtspsrc->location);
|
||||||
|
g_free (rtspsrc->req_location);
|
||||||
g_free (rtspsrc->content_base);
|
g_free (rtspsrc->content_base);
|
||||||
rtsp_url_free (rtspsrc->url);
|
rtsp_url_free (rtspsrc->url);
|
||||||
|
|
||||||
|
@ -439,7 +446,8 @@ gst_rtspsrc_create_stream (GstRTSPSrc * src, SDPMessage * sdp, gint idx)
|
||||||
stream->setup_url =
|
stream->setup_url =
|
||||||
g_strdup_printf ("%s%s", src->content_base, control_url);
|
g_strdup_printf ("%s%s", src->content_base, control_url);
|
||||||
else
|
else
|
||||||
stream->setup_url = g_strdup_printf ("%s/%s", src->location, control_url);
|
stream->setup_url =
|
||||||
|
g_strdup_printf ("%s/%s", src->req_location, control_url);
|
||||||
}
|
}
|
||||||
GST_DEBUG_OBJECT (src, " setup: %s", GST_STR_NULL (stream->setup_url));
|
GST_DEBUG_OBJECT (src, " setup: %s", GST_STR_NULL (stream->setup_url));
|
||||||
|
|
||||||
|
@ -1533,6 +1541,145 @@ send_error:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef GST_DISABLE_GST_DEBUG
|
||||||
|
const gchar *
|
||||||
|
rtsp_auth_method_to_string (RTSPAuthMethod method)
|
||||||
|
{
|
||||||
|
gint index = 0;
|
||||||
|
|
||||||
|
while (method != 0) {
|
||||||
|
index++;
|
||||||
|
method >>= 1;
|
||||||
|
}
|
||||||
|
switch (index) {
|
||||||
|
case 0:
|
||||||
|
return "None";
|
||||||
|
case 1:
|
||||||
|
return "Basic";
|
||||||
|
case 2:
|
||||||
|
return "Digest";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Parse a WWW-Authenticate Response header and determine the
|
||||||
|
* available authentication methods
|
||||||
|
* FIXME: To implement digest or other auth types, we should extract
|
||||||
|
* the authentication tokens that the server provided for each method
|
||||||
|
* into an array of structures and give those to the connection object.
|
||||||
|
*
|
||||||
|
* This code should also cope with the fact that each WWW-Authenticate
|
||||||
|
* header can contain multiple challenge methods + tokens
|
||||||
|
*
|
||||||
|
* At the moment, we just do a minimal check for Basic auth and don't
|
||||||
|
* even parse out the realm */
|
||||||
|
static void
|
||||||
|
gst_rtspsrc_parse_auth_hdr (gchar * hdr, RTSPAuthMethod * methods)
|
||||||
|
{
|
||||||
|
gchar *start;
|
||||||
|
|
||||||
|
g_return_if_fail (hdr != NULL);
|
||||||
|
g_return_if_fail (methods != NULL);
|
||||||
|
|
||||||
|
/* Skip whitespace at the start of the string */
|
||||||
|
for (start = hdr; start[0] != '\0' && g_ascii_isspace (start[0]); start++);
|
||||||
|
|
||||||
|
if (g_ascii_strncasecmp (start, "basic", 5) == 0)
|
||||||
|
*methods |= RTSP_AUTH_BASIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_rtspsrc_setup_auth:
|
||||||
|
* @src: the rtsp source
|
||||||
|
*
|
||||||
|
* Configure a username and password and auth method on the
|
||||||
|
* connection object based on a response we received from the
|
||||||
|
* peer.
|
||||||
|
*
|
||||||
|
* Currently, this requires that a username and password were supplied
|
||||||
|
* in the uri. In the future, they may be requested on demand by sending
|
||||||
|
* a message up the bus.
|
||||||
|
*
|
||||||
|
* Returns: TRUE if authentication information could be set up correctly.
|
||||||
|
*/
|
||||||
|
static gboolean
|
||||||
|
gst_rtspsrc_setup_auth (GstRTSPSrc * src, RTSPMessage * response)
|
||||||
|
{
|
||||||
|
gchar *user = NULL;
|
||||||
|
gchar *pass = NULL;
|
||||||
|
RTSPAuthMethod avail_methods = RTSP_AUTH_NONE;
|
||||||
|
RTSPAuthMethod method;
|
||||||
|
RTSPResult auth_result;
|
||||||
|
gchar *hdr;
|
||||||
|
|
||||||
|
/* Identify the available auth methods and see if any are supported */
|
||||||
|
if (rtsp_message_get_header (response, RTSP_HDR_WWW_AUTHENTICATE, &hdr) ==
|
||||||
|
RTSP_OK) {
|
||||||
|
gst_rtspsrc_parse_auth_hdr (hdr, &avail_methods);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (avail_methods == RTSP_AUTH_NONE)
|
||||||
|
goto no_auth_available;
|
||||||
|
|
||||||
|
/* FIXME: For digest auth, if the response indicates that the session
|
||||||
|
* data are stale, we just update them in the connection object and
|
||||||
|
* return TRUE to retry the request */
|
||||||
|
|
||||||
|
/* Do we have username and password available? */
|
||||||
|
if (src->url != NULL && !src->tried_url_auth) {
|
||||||
|
user = src->url->user;
|
||||||
|
pass = src->url->passwd;
|
||||||
|
src->tried_url_auth = TRUE;
|
||||||
|
GST_DEBUG_OBJECT (src,
|
||||||
|
"Attempting authentication using credentials from the URL");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: If the url didn't contain username and password or we tried them
|
||||||
|
* already, request a username and passwd from the application via some kind
|
||||||
|
* of credentials request message */
|
||||||
|
|
||||||
|
/* If we don't have a username and passwd at this point, bail out. */
|
||||||
|
if (user == NULL || pass == NULL)
|
||||||
|
goto no_user_pass;
|
||||||
|
|
||||||
|
/* Try to configure for each available authentication method, strongest to
|
||||||
|
* weakest */
|
||||||
|
for (method = RTSP_AUTH_MAX; method != RTSP_AUTH_NONE; method >>= 1) {
|
||||||
|
/* Check if this method is available on the server */
|
||||||
|
if ((method & avail_methods) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Pass the credentials to the connection to try on the next request */
|
||||||
|
auth_result =
|
||||||
|
rtsp_connection_set_auth (src->connection, method, user, pass);
|
||||||
|
/* INVAL indicates an invalid username/passwd were supplied, so we'll just
|
||||||
|
* ignore it and end up retrying later */
|
||||||
|
if (auth_result == RTSP_OK || auth_result == RTSP_EINVAL) {
|
||||||
|
GST_DEBUG_OBJECT (src, "Attempting %s authentication",
|
||||||
|
rtsp_auth_method_to_string (method));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method == RTSP_AUTH_NONE)
|
||||||
|
goto no_auth_available;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
no_auth_available:
|
||||||
|
/* Output an error indicating that we couldn't connect because there were
|
||||||
|
* no supported authentication protocols */
|
||||||
|
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
|
||||||
|
("No supported authentication protocol was found"));
|
||||||
|
return FALSE;
|
||||||
|
no_user_pass:
|
||||||
|
/* We don't fire an error message, we just return FALSE and let the
|
||||||
|
* normal NOT_AUTHORIZED error be propagated */
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_rtspsrc_send:
|
* gst_rtspsrc_send:
|
||||||
* @src: the rtsp source
|
* @src: the rtsp source
|
||||||
|
@ -1548,11 +1695,64 @@ send_error:
|
||||||
* If @code is NULL, this function will return FALSE (with an invalid @response
|
* If @code is NULL, this function will return FALSE (with an invalid @response
|
||||||
* message) if the response code was not 200 (OK).
|
* message) if the response code was not 200 (OK).
|
||||||
*
|
*
|
||||||
|
* If the attempt results in an authentication failure, then this will attempt
|
||||||
|
* to retrieve authentication credentials via gst_rtspsrc_setup_auth and retry
|
||||||
|
* the request.
|
||||||
|
*
|
||||||
* Returns: TRUE if the processing was successful.
|
* Returns: TRUE if the processing was successful.
|
||||||
*/
|
*/
|
||||||
gboolean
|
gboolean
|
||||||
gst_rtspsrc_send (GstRTSPSrc * src, RTSPMessage * request,
|
gst_rtspsrc_send (GstRTSPSrc * src, RTSPMessage * request,
|
||||||
RTSPMessage * response, RTSPStatusCode * code)
|
RTSPMessage * response, RTSPStatusCode * code)
|
||||||
|
{
|
||||||
|
RTSPStatusCode int_code = RTSP_STS_OK;
|
||||||
|
gboolean res;
|
||||||
|
gboolean retry;
|
||||||
|
|
||||||
|
do {
|
||||||
|
retry = FALSE;
|
||||||
|
res = gst_rtspsrc_try_send (src, request, response, &int_code);
|
||||||
|
|
||||||
|
if (int_code == RTSP_STS_UNAUTHORIZED) {
|
||||||
|
if (gst_rtspsrc_setup_auth (src, response)) {
|
||||||
|
/* Try the request/response again after configuring the auth info
|
||||||
|
* and loop again */
|
||||||
|
retry = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (retry == TRUE);
|
||||||
|
|
||||||
|
/* If the user requested the code, let them handle errors, otherwise
|
||||||
|
* post an error below */
|
||||||
|
if (code != NULL)
|
||||||
|
*code = int_code;
|
||||||
|
else if (int_code != RTSP_STS_OK)
|
||||||
|
goto error_response;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
|
||||||
|
error_response:
|
||||||
|
{
|
||||||
|
switch (response->type_data.response.code) {
|
||||||
|
case RTSP_STS_NOT_FOUND:
|
||||||
|
GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL), ("%s",
|
||||||
|
response->type_data.response.reason));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
|
||||||
|
("Got error response: %d (%s).", response->type_data.response.code,
|
||||||
|
response->type_data.response.reason));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* we return FALSE so we should unset the response ourselves */
|
||||||
|
rtsp_message_unset (response);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_rtspsrc_try_send (GstRTSPSrc * src, RTSPMessage * request,
|
||||||
|
RTSPMessage * response, RTSPStatusCode * code)
|
||||||
{
|
{
|
||||||
RTSPResult res;
|
RTSPResult res;
|
||||||
RTSPStatusCode thecode;
|
RTSPStatusCode thecode;
|
||||||
|
@ -1590,12 +1790,14 @@ next:
|
||||||
}
|
}
|
||||||
|
|
||||||
thecode = response->type_data.response.code;
|
thecode = response->type_data.response.code;
|
||||||
/* if the caller wanted the result code, we store it. Else we check if it's
|
|
||||||
* OK. */
|
/* if the caller wanted the result code, we store it. */
|
||||||
if (code)
|
if (code)
|
||||||
*code = thecode;
|
*code = thecode;
|
||||||
else if (thecode != RTSP_STS_OK)
|
|
||||||
goto error_response;
|
/* If the request didn't succeed, bail out before doing any more */
|
||||||
|
if (thecode != RTSP_STS_OK)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
/* store new content base if any */
|
/* store new content base if any */
|
||||||
rtsp_message_get_header (response, RTSP_HDR_CONTENT_BASE, &content_base);
|
rtsp_message_get_header (response, RTSP_HDR_CONTENT_BASE, &content_base);
|
||||||
|
@ -1631,23 +1833,6 @@ handle_request_failed:
|
||||||
/* ERROR was posted */
|
/* ERROR was posted */
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
error_response:
|
|
||||||
{
|
|
||||||
switch (response->type_data.response.code) {
|
|
||||||
case RTSP_STS_NOT_FOUND:
|
|
||||||
GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL), ("%s",
|
|
||||||
response->type_data.response.reason));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
|
|
||||||
("Got error response: %d (%s).", response->type_data.response.code,
|
|
||||||
response->type_data.response.reason));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* we return FALSE so we should unset the response ourselves */
|
|
||||||
rtsp_message_unset (response);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* parse the response and collect all the supported methods. We need this
|
/* parse the response and collect all the supported methods. We need this
|
||||||
|
@ -2058,20 +2243,21 @@ gst_rtspsrc_open (GstRTSPSrc * src)
|
||||||
/* can't continue without a valid url */
|
/* can't continue without a valid url */
|
||||||
if (G_UNLIKELY (src->url == NULL))
|
if (G_UNLIKELY (src->url == NULL))
|
||||||
goto no_url;
|
goto no_url;
|
||||||
|
src->tried_url_auth = FALSE;
|
||||||
|
|
||||||
/* create connection */
|
/* create connection */
|
||||||
GST_DEBUG_OBJECT (src, "creating connection (%s)...", src->location);
|
GST_DEBUG_OBJECT (src, "creating connection (%s)...", src->req_location);
|
||||||
if ((res = rtsp_connection_create (src->url, &src->connection)) < 0)
|
if ((res = rtsp_connection_create (src->url, &src->connection)) < 0)
|
||||||
goto could_not_create;
|
goto could_not_create;
|
||||||
|
|
||||||
/* connect */
|
/* connect */
|
||||||
GST_DEBUG_OBJECT (src, "connecting (%s)...", src->location);
|
GST_DEBUG_OBJECT (src, "connecting (%s)...", src->req_location);
|
||||||
if ((res = rtsp_connection_connect (src->connection)) < 0)
|
if ((res = rtsp_connection_connect (src->connection)) < 0)
|
||||||
goto could_not_connect;
|
goto could_not_connect;
|
||||||
|
|
||||||
/* create OPTIONS */
|
/* create OPTIONS */
|
||||||
GST_DEBUG_OBJECT (src, "create options...");
|
GST_DEBUG_OBJECT (src, "create options...");
|
||||||
res = rtsp_message_init_request (&request, RTSP_OPTIONS, src->location);
|
res = rtsp_message_init_request (&request, RTSP_OPTIONS, src->req_location);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
goto create_request_failed;
|
goto create_request_failed;
|
||||||
|
|
||||||
|
@ -2086,7 +2272,7 @@ gst_rtspsrc_open (GstRTSPSrc * src)
|
||||||
|
|
||||||
/* create DESCRIBE */
|
/* create DESCRIBE */
|
||||||
GST_DEBUG_OBJECT (src, "create describe...");
|
GST_DEBUG_OBJECT (src, "create describe...");
|
||||||
res = rtsp_message_init_request (&request, RTSP_DESCRIBE, src->location);
|
res = rtsp_message_init_request (&request, RTSP_DESCRIBE, src->req_location);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
goto create_request_failed;
|
goto create_request_failed;
|
||||||
|
|
||||||
|
@ -2177,11 +2363,8 @@ create_request_failed:
|
||||||
}
|
}
|
||||||
send_error:
|
send_error:
|
||||||
{
|
{
|
||||||
gchar *str = rtsp_strresult (res);
|
/* Don't post a message - the rtsp_send method will have
|
||||||
|
* taken care of it because we passed NULL for the response code */
|
||||||
GST_ELEMENT_ERROR (src, RESOURCE, WRITE, (NULL),
|
|
||||||
("Could not send message. (%s)", str));
|
|
||||||
g_free (str);
|
|
||||||
goto cleanup_error;
|
goto cleanup_error;
|
||||||
}
|
}
|
||||||
methods_error:
|
methods_error:
|
||||||
|
@ -2232,7 +2415,8 @@ gst_rtspsrc_close (GstRTSPSrc * src)
|
||||||
|
|
||||||
if (src->methods & RTSP_PLAY) {
|
if (src->methods & RTSP_PLAY) {
|
||||||
/* do TEARDOWN */
|
/* do TEARDOWN */
|
||||||
res = rtsp_message_init_request (&request, RTSP_TEARDOWN, src->location);
|
res =
|
||||||
|
rtsp_message_init_request (&request, RTSP_TEARDOWN, src->req_location);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
goto create_request_failed;
|
goto create_request_failed;
|
||||||
|
|
||||||
|
@ -2317,7 +2501,7 @@ gst_rtspsrc_play (GstRTSPSrc * src)
|
||||||
GST_DEBUG_OBJECT (src, "PLAY...");
|
GST_DEBUG_OBJECT (src, "PLAY...");
|
||||||
|
|
||||||
/* do play */
|
/* do play */
|
||||||
res = rtsp_message_init_request (&request, RTSP_PLAY, src->location);
|
res = rtsp_message_init_request (&request, RTSP_PLAY, src->req_location);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
goto create_request_failed;
|
goto create_request_failed;
|
||||||
|
|
||||||
|
@ -2378,7 +2562,7 @@ gst_rtspsrc_pause (GstRTSPSrc * src)
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (src, "PAUSE...");
|
GST_DEBUG_OBJECT (src, "PAUSE...");
|
||||||
/* do pause */
|
/* do pause */
|
||||||
res = rtsp_message_init_request (&request, RTSP_PAUSE, src->location);
|
res = rtsp_message_init_request (&request, RTSP_PAUSE, src->req_location);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
goto create_request_failed;
|
goto create_request_failed;
|
||||||
|
|
||||||
|
@ -2541,11 +2725,13 @@ gst_rtspsrc_uri_set_uri (GstURIHandler * handler, const gchar * uri)
|
||||||
rtsp_url_free (src->url);
|
rtsp_url_free (src->url);
|
||||||
src->url = newurl;
|
src->url = newurl;
|
||||||
g_free (src->location);
|
g_free (src->location);
|
||||||
|
g_free (src->req_location);
|
||||||
src->location = g_strdup (uri);
|
src->location = g_strdup (uri);
|
||||||
if (!g_str_has_prefix (src->location, "rtsp://"))
|
src->req_location = rtsp_url_get_request_uri (src->url);
|
||||||
memmove (src->location + 4, src->location + 5, strlen (src->location) - 4);
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (src, "set uri: %s", GST_STR_NULL (uri));
|
GST_DEBUG_OBJECT (src, "set uri: %s", GST_STR_NULL (uri));
|
||||||
|
GST_DEBUG_OBJECT (src, "request uri is: %s",
|
||||||
|
GST_STR_NULL (src->req_location));
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
|
|
@ -130,6 +130,7 @@ struct _GstRTSPSrc {
|
||||||
|
|
||||||
/* properties */
|
/* properties */
|
||||||
gchar *location;
|
gchar *location;
|
||||||
|
gchar *req_location; /* Sanitised URL to use in network requests */
|
||||||
RTSPUrl *url;
|
RTSPUrl *url;
|
||||||
RTSPLowerTrans protocols;
|
RTSPLowerTrans protocols;
|
||||||
gboolean debug;
|
gboolean debug;
|
||||||
|
@ -139,6 +140,7 @@ struct _GstRTSPSrc {
|
||||||
/* state */
|
/* state */
|
||||||
gchar *content_base;
|
gchar *content_base;
|
||||||
RTSPLowerTrans cur_protocols;
|
RTSPLowerTrans cur_protocols;
|
||||||
|
gboolean tried_url_auth;
|
||||||
|
|
||||||
/* supported methods */
|
/* supported methods */
|
||||||
gint methods;
|
gint methods;
|
||||||
|
|
|
@ -143,6 +143,10 @@ rtsp_connection_create (RTSPUrl * url, RTSPConnection ** conn)
|
||||||
newconn->session_id[0] = 0;
|
newconn->session_id[0] = 0;
|
||||||
newconn->state = RTSP_STATE_INIT;
|
newconn->state = RTSP_STATE_INIT;
|
||||||
|
|
||||||
|
newconn->auth_method = RTSP_AUTH_NONE;
|
||||||
|
newconn->username = NULL;
|
||||||
|
newconn->passwd = NULL;
|
||||||
|
|
||||||
*conn = newconn;
|
*conn = newconn;
|
||||||
|
|
||||||
return RTSP_OK;
|
return RTSP_OK;
|
||||||
|
@ -231,6 +235,30 @@ append_header (gint key, gchar * value, GString * str)
|
||||||
g_string_append_printf (str, "%s: %s\r\n", keystr, value);
|
g_string_append_printf (str, "%s: %s\r\n", keystr, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
append_auth_header (RTSPConnection * conn, RTSPMessage * message, GString * str)
|
||||||
|
{
|
||||||
|
switch (conn->auth_method) {
|
||||||
|
case RTSP_AUTH_BASIC:{
|
||||||
|
gchar *user_pass =
|
||||||
|
g_strdup_printf ("%s:%s", conn->username, conn->passwd);
|
||||||
|
gchar *user_pass64 =
|
||||||
|
g_base64_encode ((guchar *) user_pass, strlen (user_pass));
|
||||||
|
gchar *auth_string = g_strdup_printf ("Basic %s", user_pass64);
|
||||||
|
|
||||||
|
append_header (RTSP_HDR_AUTHORIZATION, auth_string, str);
|
||||||
|
|
||||||
|
g_free (user_pass);
|
||||||
|
g_free (user_pass64);
|
||||||
|
g_free (auth_string);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
/* Nothing to do */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RTSPResult
|
RTSPResult
|
||||||
rtsp_connection_send (RTSPConnection * conn, RTSPMessage * message)
|
rtsp_connection_send (RTSPConnection * conn, RTSPMessage * message)
|
||||||
{
|
{
|
||||||
|
@ -278,12 +306,15 @@ rtsp_connection_send (RTSPConnection * conn, RTSPMessage * message)
|
||||||
|
|
||||||
/* append session id if we have one */
|
/* append session id if we have one */
|
||||||
if (conn->session_id[0] != '\0') {
|
if (conn->session_id[0] != '\0') {
|
||||||
rtsp_message_add_header (message, RTSP_HDR_SESSION, conn->session_id);
|
append_header (RTSP_HDR_SESSION, conn->session_id, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* append headers */
|
/* append headers */
|
||||||
g_hash_table_foreach (message->hdr_fields, (GHFunc) append_header, str);
|
g_hash_table_foreach (message->hdr_fields, (GHFunc) append_header, str);
|
||||||
|
|
||||||
|
/* Append any authentication headers */
|
||||||
|
append_auth_header (conn, message, str);
|
||||||
|
|
||||||
/* append Content-Length and body if needed */
|
/* append Content-Length and body if needed */
|
||||||
if (message->body != NULL && message->body_size > 0) {
|
if (message->body != NULL && message->body_size > 0) {
|
||||||
gchar *len;
|
gchar *len;
|
||||||
|
@ -786,6 +817,9 @@ rtsp_connection_free (RTSPConnection * conn)
|
||||||
WSACleanup ();
|
WSACleanup ();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
g_free (conn->username);
|
||||||
|
g_free (conn->passwd);
|
||||||
|
|
||||||
g_free (conn);
|
g_free (conn);
|
||||||
|
|
||||||
return RTSP_OK;
|
return RTSP_OK;
|
||||||
|
@ -812,3 +846,29 @@ rtsp_connection_flush (RTSPConnection * conn, gboolean flush)
|
||||||
}
|
}
|
||||||
return RTSP_OK;
|
return RTSP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RTSPResult
|
||||||
|
rtsp_connection_set_auth (RTSPConnection * conn, RTSPAuthMethod method,
|
||||||
|
gchar * user, gchar * pass)
|
||||||
|
{
|
||||||
|
/* Digest isn't implemented yet */
|
||||||
|
if (method == RTSP_AUTH_DIGEST)
|
||||||
|
return RTSP_ENOTIMPL;
|
||||||
|
|
||||||
|
/* Make sure the username and passwd are being set for authentication */
|
||||||
|
if (method == RTSP_AUTH_NONE && (user == NULL || pass == NULL))
|
||||||
|
return RTSP_EINVAL;
|
||||||
|
|
||||||
|
/* ":" chars are not allowed in usernames for basic auth */
|
||||||
|
if (method == RTSP_AUTH_BASIC && g_strrstr (user, ":") != NULL)
|
||||||
|
return RTSP_EINVAL;
|
||||||
|
|
||||||
|
g_free (conn->username);
|
||||||
|
g_free (conn->passwd);
|
||||||
|
|
||||||
|
conn->auth_method = method;
|
||||||
|
conn->username = g_strdup (user);
|
||||||
|
conn->passwd = g_strdup (pass);
|
||||||
|
|
||||||
|
return RTSP_OK;
|
||||||
|
}
|
||||||
|
|
|
@ -64,6 +64,11 @@ typedef struct _RTSPConnection
|
||||||
RTSPState state;
|
RTSPState state;
|
||||||
gint cseq; /* sequence number */
|
gint cseq; /* sequence number */
|
||||||
gchar session_id[512]; /* session id */
|
gchar session_id[512]; /* session id */
|
||||||
|
|
||||||
|
/* Authentication */
|
||||||
|
RTSPAuthMethod auth_method;
|
||||||
|
gchar *username;
|
||||||
|
gchar *passwd;
|
||||||
} RTSPConnection;
|
} RTSPConnection;
|
||||||
|
|
||||||
/* opening/closing a connection */
|
/* opening/closing a connection */
|
||||||
|
@ -78,6 +83,10 @@ RTSPResult rtsp_connection_receive (RTSPConnection *conn, RTSPMessage *mess
|
||||||
|
|
||||||
RTSPResult rtsp_connection_flush (RTSPConnection *conn, gboolean flush);
|
RTSPResult rtsp_connection_flush (RTSPConnection *conn, gboolean flush);
|
||||||
|
|
||||||
|
/* Configure Authentication data */
|
||||||
|
RTSPResult rtsp_connection_set_auth (RTSPConnection *conn,
|
||||||
|
RTSPAuthMethod method, gchar *user, gchar *pass);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __RTSP_CONNECTION_H__ */
|
#endif /* __RTSP_CONNECTION_H__ */
|
||||||
|
|
|
@ -99,6 +99,16 @@ typedef enum {
|
||||||
RTSP_TEARDOWN = (1 << 10),
|
RTSP_TEARDOWN = (1 << 10),
|
||||||
} RTSPMethod;
|
} RTSPMethod;
|
||||||
|
|
||||||
|
/* Authentication methods, ordered by strength */
|
||||||
|
typedef enum {
|
||||||
|
RTSP_AUTH_NONE = 0x00,
|
||||||
|
RTSP_AUTH_BASIC = 0x01,
|
||||||
|
RTSP_AUTH_DIGEST = 0x02
|
||||||
|
} RTSPAuthMethod;
|
||||||
|
|
||||||
|
/* Strongest available authentication method */
|
||||||
|
#define RTSP_AUTH_MAX RTSP_AUTH_DIGEST
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
RTSP_HDR_INVALID,
|
RTSP_HDR_INVALID,
|
||||||
|
|
||||||
|
|
|
@ -177,3 +177,20 @@ rtsp_url_get_port (RTSPUrl * url, guint16 * port)
|
||||||
|
|
||||||
return RTSP_OK;
|
return RTSP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gchar *
|
||||||
|
rtsp_url_get_request_uri (RTSPUrl * url)
|
||||||
|
{
|
||||||
|
gchar *uri;
|
||||||
|
|
||||||
|
g_return_val_if_fail (url != NULL, NULL);
|
||||||
|
|
||||||
|
if (url->port != 0) {
|
||||||
|
uri = g_strdup_printf ("rtsp://%s:%u/%s", url->host, url->port,
|
||||||
|
url->abspath);
|
||||||
|
} else {
|
||||||
|
uri = g_strdup_printf ("rtsp://%s/%s", url->host, url->abspath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
|
|
|
@ -64,6 +64,7 @@ typedef struct _RTSPUrl {
|
||||||
|
|
||||||
RTSPResult rtsp_url_parse (const gchar *urlstr, RTSPUrl **url);
|
RTSPResult rtsp_url_parse (const gchar *urlstr, RTSPUrl **url);
|
||||||
void rtsp_url_free (RTSPUrl *url);
|
void rtsp_url_free (RTSPUrl *url);
|
||||||
|
gchar *rtsp_url_get_request_uri (RTSPUrl *url);
|
||||||
|
|
||||||
RTSPResult rtsp_url_set_port (RTSPUrl *url, guint16 port);
|
RTSPResult rtsp_url_set_port (RTSPUrl *url, guint16 port);
|
||||||
RTSPResult rtsp_url_get_port (RTSPUrl *url, guint16 *port);
|
RTSPResult rtsp_url_get_port (RTSPUrl *url, guint16 *port);
|
||||||
|
|
Loading…
Reference in a new issue