mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-29 13:11:06 +00:00
rtspconnection: support redirect when using tunnel
- Support HTTP redirect codes (301,302,307,308) on response to GET. "Location" field is extracted and used for following GET and POST. - Notify caller a redirect took place using return value - log source and destination url on redirect Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5222>
This commit is contained in:
parent
f1ad885c9b
commit
13c5406747
3 changed files with 187 additions and 41 deletions
|
@ -2997,6 +2997,9 @@ UTC times will be converted to nanoseconds since 1900.</doc>
|
||||||
<member name="ok" value="0" c:identifier="GST_RTSP_OK" glib:nick="ok">
|
<member name="ok" value="0" c:identifier="GST_RTSP_OK" glib:nick="ok">
|
||||||
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/rtsp/gstrtspdefs.h">no error</doc>
|
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/rtsp/gstrtspdefs.h">no error</doc>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="ok_redirect" value="1" c:identifier="GST_RTSP_OK_REDIRECT" version="1.24" glib:nick="ok-redirect">
|
||||||
|
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/rtsp/gstrtspdefs.h">RTSP request is successful, but was redirected.</doc>
|
||||||
|
</member>
|
||||||
<member name="error" value="-1" c:identifier="GST_RTSP_ERROR" glib:nick="error">
|
<member name="error" value="-1" c:identifier="GST_RTSP_ERROR" glib:nick="error">
|
||||||
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/rtsp/gstrtspdefs.h">some unspecified error occurred</doc>
|
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/rtsp/gstrtspdefs.h">some unspecified error occurred</doc>
|
||||||
</member>
|
</member>
|
||||||
|
@ -3094,6 +3097,12 @@ UTC times will be converted to nanoseconds since 1900.</doc>
|
||||||
</member>
|
</member>
|
||||||
<member name="use_proxy" value="305" c:identifier="GST_RTSP_STS_USE_PROXY" glib:nick="use-proxy">
|
<member name="use_proxy" value="305" c:identifier="GST_RTSP_STS_USE_PROXY" glib:nick="use-proxy">
|
||||||
</member>
|
</member>
|
||||||
|
<member name="redirect_temporarily" value="307" c:identifier="GST_RTSP_STS_REDIRECT_TEMPORARILY" version="1.24" glib:nick="redirect-temporarily">
|
||||||
|
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/rtsp/gstrtspdefs.h">RTSP request is temporarily redirected</doc>
|
||||||
|
</member>
|
||||||
|
<member name="redirect_permanently" value="308" c:identifier="GST_RTSP_STS_REDIRECT_PERMANENTLY" version="1.24" glib:nick="redirect-permanently">
|
||||||
|
<doc xml:space="preserve" filename="../subprojects/gst-plugins-base/gst-libs/gst/rtsp/gstrtspdefs.h">RTSP request is permanently redirected</doc>
|
||||||
|
</member>
|
||||||
<member name="bad_request" value="400" c:identifier="GST_RTSP_STS_BAD_REQUEST" glib:nick="bad-request">
|
<member name="bad_request" value="400" c:identifier="GST_RTSP_STS_BAD_REQUEST" glib:nick="bad-request">
|
||||||
</member>
|
</member>
|
||||||
<member name="unauthorized" value="401" c:identifier="GST_RTSP_STS_UNAUTHORIZED" glib:nick="unauthorized">
|
<member name="unauthorized" value="401" c:identifier="GST_RTSP_STS_UNAUTHORIZED" glib:nick="unauthorized">
|
||||||
|
|
|
@ -362,6 +362,26 @@ socket_client_event (GSocketClient * client, GSocketClientEvent event,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
stream0_reset (GstRTSPConnection * conn)
|
||||||
|
{
|
||||||
|
if (conn->stream0) {
|
||||||
|
g_object_unref (conn->stream0);
|
||||||
|
conn->stream0 = NULL;
|
||||||
|
conn->socket0 = NULL;
|
||||||
|
}
|
||||||
|
conn->input_stream = NULL;
|
||||||
|
conn->output_stream = NULL;
|
||||||
|
g_free (conn->remote_ip);
|
||||||
|
|
||||||
|
conn->remote_ip = NULL;
|
||||||
|
conn->read_socket = NULL;
|
||||||
|
conn->write_socket = NULL;
|
||||||
|
conn->read_socket_used = FALSE;
|
||||||
|
conn->write_socket_used = FALSE;
|
||||||
|
conn->control_stream = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* transfer full */
|
/* transfer full */
|
||||||
static GCancellable *
|
static GCancellable *
|
||||||
get_cancellable (GstRTSPConnection * conn)
|
get_cancellable (GstRTSPConnection * conn)
|
||||||
|
@ -892,7 +912,7 @@ add_extra_headers (GstRTSPMessage * msg, GArray * headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
static GstRTSPResult
|
static GstRTSPResult
|
||||||
setup_tunneling (GstRTSPConnection * conn, gint64 timeout, gchar * uri,
|
setup_tunneling (GstRTSPConnection * conn, gint64 timeout, gchar ** req_uri,
|
||||||
GstRTSPMessage * response)
|
GstRTSPMessage * response)
|
||||||
{
|
{
|
||||||
gint i;
|
gint i;
|
||||||
|
@ -909,6 +929,10 @@ setup_tunneling (GstRTSPConnection * conn, gint64 timeout, gchar * uri,
|
||||||
gchar *request_uri = NULL;
|
gchar *request_uri = NULL;
|
||||||
gchar *host = NULL;
|
gchar *host = NULL;
|
||||||
GCancellable *cancellable;
|
GCancellable *cancellable;
|
||||||
|
gchar *uri;
|
||||||
|
|
||||||
|
g_return_val_if_fail (req_uri != NULL, GST_RTSP_EINVAL);
|
||||||
|
uri = *req_uri;
|
||||||
|
|
||||||
url = conn->url;
|
url = conn->url;
|
||||||
|
|
||||||
|
@ -952,10 +976,35 @@ setup_tunneling (GstRTSPConnection * conn, gint64 timeout, gchar * uri,
|
||||||
read_failed);
|
read_failed);
|
||||||
conn->manual_http = old_http;
|
conn->manual_http = old_http;
|
||||||
|
|
||||||
if (response->type != GST_RTSP_MESSAGE_HTTP_RESPONSE ||
|
if (response->type != GST_RTSP_MESSAGE_HTTP_RESPONSE)
|
||||||
response->type_data.response.code != GST_RTSP_STS_OK)
|
|
||||||
goto wrong_result;
|
goto wrong_result;
|
||||||
|
|
||||||
|
switch (response->type_data.response.code) {
|
||||||
|
case GST_RTSP_STS_OK:
|
||||||
|
break;
|
||||||
|
case GST_RTSP_STS_MOVED_PERMANENTLY:
|
||||||
|
case GST_RTSP_STS_MOVE_TEMPORARILY:
|
||||||
|
case GST_RTSP_STS_REDIRECT_TEMPORARILY:
|
||||||
|
case GST_RTSP_STS_REDIRECT_PERMANENTLY:
|
||||||
|
{
|
||||||
|
gchar *location_val = NULL;
|
||||||
|
gst_rtsp_message_get_header (response, GST_RTSP_HDR_LOCATION,
|
||||||
|
&location_val, 0);
|
||||||
|
|
||||||
|
if (location_val != NULL) {
|
||||||
|
GST_TRACE ("redirect (%d) to %s",
|
||||||
|
response->type_data.response.code, location_val);
|
||||||
|
g_free (uri);
|
||||||
|
uri = g_strdup (location_val);
|
||||||
|
*req_uri = uri;
|
||||||
|
res = GST_RTSP_OK_REDIRECT;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
goto wrong_result;
|
||||||
|
}
|
||||||
|
|
||||||
if (!conn->ignore_x_server_reply &&
|
if (!conn->ignore_x_server_reply &&
|
||||||
gst_rtsp_message_get_header (response, GST_RTSP_HDR_X_SERVER_IP_ADDRESS,
|
gst_rtsp_message_get_header (response, GST_RTSP_HDR_X_SERVER_IP_ADDRESS,
|
||||||
&value, 0) == GST_RTSP_OK) {
|
&value, 0) == GST_RTSP_OK) {
|
||||||
|
@ -1102,15 +1151,17 @@ GstRTSPResult
|
||||||
gst_rtsp_connection_connect_with_response_usec (GstRTSPConnection * conn,
|
gst_rtsp_connection_connect_with_response_usec (GstRTSPConnection * conn,
|
||||||
gint64 timeout, GstRTSPMessage * response)
|
gint64 timeout, GstRTSPMessage * response)
|
||||||
{
|
{
|
||||||
GstRTSPResult res;
|
GstRTSPResult res = GST_RTSP_OK;
|
||||||
GSocketConnection *connection;
|
GSocketConnection *connection;
|
||||||
GSocket *socket;
|
GSocket *socket;
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
gchar *connection_uri, *request_uri, *remote_ip;
|
gchar *connection_uri, *request_uri, *remote_ip, *query = NULL, *path = NULL;
|
||||||
GstClockTime to;
|
GstClockTime to;
|
||||||
guint16 url_port;
|
guint16 url_port;
|
||||||
GstRTSPUrl *url;
|
GstRTSPUrl *url;
|
||||||
GCancellable *cancellable;
|
GCancellable *cancellable;
|
||||||
|
guint redirect_cnt = 0;
|
||||||
|
GstUri *uri = NULL;
|
||||||
|
|
||||||
g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
|
g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
|
||||||
g_return_val_if_fail (conn->url != NULL, GST_RTSP_EINVAL);
|
g_return_val_if_fail (conn->url != NULL, GST_RTSP_EINVAL);
|
||||||
|
@ -1130,54 +1181,110 @@ gst_rtsp_connection_connect_with_response_usec (GstRTSPConnection * conn,
|
||||||
connection_uri = gst_rtsp_url_get_request_uri (url);
|
connection_uri = gst_rtsp_url_get_request_uri (url);
|
||||||
}
|
}
|
||||||
|
|
||||||
cancellable = get_cancellable (conn);
|
while (res == GST_RTSP_OK) {
|
||||||
|
cancellable = get_cancellable (conn);
|
||||||
|
|
||||||
if (conn->proxy_host) {
|
if (conn->proxy_host) {
|
||||||
connection = g_socket_client_connect_to_host (conn->client,
|
connection = g_socket_client_connect_to_host (conn->client,
|
||||||
conn->proxy_host, conn->proxy_port, cancellable, &error);
|
conn->proxy_host, conn->proxy_port, cancellable, &error);
|
||||||
request_uri = g_strdup (connection_uri);
|
request_uri = g_strdup (connection_uri);
|
||||||
} else {
|
} else {
|
||||||
connection = g_socket_client_connect_to_uri (conn->client,
|
if (uri != NULL) {
|
||||||
connection_uri, url_port, cancellable, &error);
|
url_port = gst_uri_get_port (uri);
|
||||||
|
}
|
||||||
|
connection = g_socket_client_connect_to_uri (conn->client,
|
||||||
|
connection_uri, url_port, cancellable, &error);
|
||||||
|
|
||||||
/* use the relative component of the uri for non-proxy connections */
|
if (uri == NULL) {
|
||||||
request_uri = g_strdup_printf ("%s%s%s", url->abspath,
|
/* Use the relative component of the uri for non-proxy connections.
|
||||||
url->query ? "?" : "", url->query ? url->query : "");
|
* Note: request_uri is not a complete URI, it only contain path +
|
||||||
}
|
* query.*/
|
||||||
|
request_uri = g_strdup_printf ("%s%s%s", url->abspath,
|
||||||
|
url->query ? "?" : "", url->query ? url->query : "");
|
||||||
|
} else {
|
||||||
|
path = gst_uri_get_path (uri);
|
||||||
|
query = gst_uri_get_query_string (uri);
|
||||||
|
request_uri = g_strdup_printf ("%s%s%s",
|
||||||
|
path, query ? "?" : "", query ? query : "");
|
||||||
|
}
|
||||||
|
g_free (path);
|
||||||
|
g_free (query);
|
||||||
|
}
|
||||||
|
|
||||||
g_clear_object (&cancellable);
|
g_clear_object (&cancellable);
|
||||||
|
|
||||||
if (connection == NULL)
|
if (connection == NULL)
|
||||||
goto connect_failed;
|
goto connect_failed;
|
||||||
|
|
||||||
/* get remote address */
|
/* get remote address */
|
||||||
socket = g_socket_connection_get_socket (connection);
|
socket = g_socket_connection_get_socket (connection);
|
||||||
|
|
||||||
if (!collect_addresses (socket, &remote_ip, NULL, TRUE, &error))
|
if (!collect_addresses (socket, &remote_ip, NULL, TRUE, &error))
|
||||||
goto remote_address_failed;
|
goto remote_address_failed;
|
||||||
|
|
||||||
g_free (conn->remote_ip);
|
g_free (conn->remote_ip);
|
||||||
conn->remote_ip = remote_ip;
|
conn->remote_ip = remote_ip;
|
||||||
conn->stream0 = G_IO_STREAM (connection);
|
conn->stream0 = G_IO_STREAM (connection);
|
||||||
conn->socket0 = socket;
|
conn->socket0 = socket;
|
||||||
/* this is our read socket */
|
/* this is our read socket */
|
||||||
conn->read_socket = conn->socket0;
|
conn->read_socket = conn->socket0;
|
||||||
conn->write_socket = conn->socket0;
|
conn->write_socket = conn->socket0;
|
||||||
conn->read_socket_used = FALSE;
|
conn->read_socket_used = FALSE;
|
||||||
conn->write_socket_used = FALSE;
|
conn->write_socket_used = FALSE;
|
||||||
conn->input_stream = g_io_stream_get_input_stream (conn->stream0);
|
conn->input_stream = g_io_stream_get_input_stream (conn->stream0);
|
||||||
conn->output_stream = g_io_stream_get_output_stream (conn->stream0);
|
conn->output_stream = g_io_stream_get_output_stream (conn->stream0);
|
||||||
conn->control_stream = NULL;
|
conn->control_stream = NULL;
|
||||||
|
|
||||||
if (conn->tunneled) {
|
if (conn->tunneled) {
|
||||||
res = setup_tunneling (conn, timeout, request_uri, response);
|
res = setup_tunneling (conn, timeout, &request_uri, response);
|
||||||
if (res != GST_RTSP_OK)
|
if (res != GST_RTSP_OK) {
|
||||||
goto tunneling_failed;
|
if (res == GST_RTSP_OK_REDIRECT) {
|
||||||
|
if (conn->proxy_host) {
|
||||||
|
GST_TRACE ("redirect behind proxy is not supported");
|
||||||
|
res = GST_RTSP_ERROR;
|
||||||
|
goto tunneling_failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_LOG ("redirect from %s to %s.", connection_uri, request_uri);
|
||||||
|
|
||||||
|
stream0_reset (conn);
|
||||||
|
connection_uri = request_uri;
|
||||||
|
gst_uri_unref (uri);
|
||||||
|
|
||||||
|
uri = gst_uri_from_string (connection_uri);
|
||||||
|
if (uri == NULL) {
|
||||||
|
GST_TRACE ("failed to parse redirect uri");
|
||||||
|
res = GST_RTSP_ERROR;
|
||||||
|
goto tunneling_failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
conn->url->abspath = gst_uri_get_path (uri);
|
||||||
|
conn->url->host = g_strdup (gst_uri_get_host (uri));
|
||||||
|
conn->url->port = gst_uri_get_port (uri);
|
||||||
|
conn->url->query = gst_uri_get_query_string (uri);
|
||||||
|
res = GST_RTSP_OK;
|
||||||
|
|
||||||
|
/* at most allow 5 redirect */
|
||||||
|
if (redirect_cnt++ > 4) {
|
||||||
|
GST_TRACE ("redirect max reached");
|
||||||
|
res = GST_RTSP_ERROR;
|
||||||
|
goto tunneling_failed;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
goto tunneling_failed;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Caller must be informed */
|
||||||
|
res = GST_RTSP_OK_REDIRECT;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
g_free (connection_uri);
|
g_free (connection_uri);
|
||||||
g_free (request_uri);
|
g_free (request_uri);
|
||||||
|
|
||||||
return GST_RTSP_OK;
|
return res;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
connect_failed:
|
connect_failed:
|
||||||
|
|
|
@ -65,6 +65,7 @@ G_STMT_START { \
|
||||||
/**
|
/**
|
||||||
* GstRTSPResult:
|
* GstRTSPResult:
|
||||||
* @GST_RTSP_OK: no error
|
* @GST_RTSP_OK: no error
|
||||||
|
* @GST_RTSP_OK_REDIRECT: no error, but redirected
|
||||||
* @GST_RTSP_ERROR: some unspecified error occurred
|
* @GST_RTSP_ERROR: some unspecified error occurred
|
||||||
* @GST_RTSP_EINVAL: invalid arguments were provided to a function
|
* @GST_RTSP_EINVAL: invalid arguments were provided to a function
|
||||||
* @GST_RTSP_EINTR: an operation was canceled
|
* @GST_RTSP_EINTR: an operation was canceled
|
||||||
|
@ -87,6 +88,16 @@ G_STMT_START { \
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GST_RTSP_OK = 0,
|
GST_RTSP_OK = 0,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GST_RTSP_OK_REDIRECT:
|
||||||
|
*
|
||||||
|
* RTSP request is successful, but was redirected.
|
||||||
|
*
|
||||||
|
* Since: 1.24
|
||||||
|
*/
|
||||||
|
GST_RTSP_OK_REDIRECT = 1,
|
||||||
|
|
||||||
/* errors */
|
/* errors */
|
||||||
GST_RTSP_ERROR = -1,
|
GST_RTSP_ERROR = -1,
|
||||||
GST_RTSP_EINVAL = -2,
|
GST_RTSP_EINVAL = -2,
|
||||||
|
@ -365,6 +376,25 @@ typedef enum {
|
||||||
GST_RTSP_STS_SEE_OTHER = 303,
|
GST_RTSP_STS_SEE_OTHER = 303,
|
||||||
GST_RTSP_STS_NOT_MODIFIED = 304,
|
GST_RTSP_STS_NOT_MODIFIED = 304,
|
||||||
GST_RTSP_STS_USE_PROXY = 305,
|
GST_RTSP_STS_USE_PROXY = 305,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GST_RTSP_STS_REDIRECT_TEMPORARILY:
|
||||||
|
*
|
||||||
|
* RTSP request is temporarily redirected
|
||||||
|
*
|
||||||
|
* Since: 1.24
|
||||||
|
*/
|
||||||
|
GST_RTSP_STS_REDIRECT_TEMPORARILY = 307,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GST_RTSP_STS_REDIRECT_PERMANENTLY:
|
||||||
|
*
|
||||||
|
* RTSP request is permanently redirected
|
||||||
|
*
|
||||||
|
* Since: 1.24
|
||||||
|
*/
|
||||||
|
GST_RTSP_STS_REDIRECT_PERMANENTLY = 308,
|
||||||
|
|
||||||
GST_RTSP_STS_BAD_REQUEST = 400,
|
GST_RTSP_STS_BAD_REQUEST = 400,
|
||||||
GST_RTSP_STS_UNAUTHORIZED = 401,
|
GST_RTSP_STS_UNAUTHORIZED = 401,
|
||||||
GST_RTSP_STS_PAYMENT_REQUIRED = 402,
|
GST_RTSP_STS_PAYMENT_REQUIRED = 402,
|
||||||
|
|
Loading…
Reference in a new issue