From efd079546ae736d0e20891acd126fe1ec7e116d2 Mon Sep 17 00:00:00 2001 From: Tim-Philipp Müller Date: Fri, 2 May 2014 19:59:23 +0100 Subject: rtsp-client: handle Require headers and respond with OPTION_NOT_SUPPORTED Servers must handle Require headers and must report a failure if they don't handle any of the Required options, see RFC 2326, section 12.32: https://tools.ietf.org/html/rfc2326#page-54 https://bugzilla.gnome.org/show_bug.cgi?id=729426 --- gst/rtsp-server/rtsp-client.c | 81 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index d42f933..93d3b3f 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -502,6 +502,25 @@ send_generic_response (GstRTSPClient * client, GstRTSPStatusCode code, send_message (client, ctx, ctx->response, FALSE); } +static void +send_option_not_supported_response (GstRTSPClient * client, + GstRTSPContext * ctx, const gchar * unsupported_options) +{ + GstRTSPStatusCode code = GST_RTSP_STS_OPTION_NOT_SUPPORTED; + + gst_rtsp_message_init_response (ctx->response, code, + gst_rtsp_status_as_text (code), ctx->request); + + if (unsupported_options != NULL) { + gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_UNSUPPORTED, + unsupported_options); + } + + ctx->session = NULL; + + send_message (client, ctx, ctx->response, FALSE); +} + static gboolean paths_are_equal (const gchar * path1, const gchar * path2, gint len2) { @@ -2169,6 +2188,55 @@ client_session_finalized (GstRTSPClient * client, GstRTSPSession * session) } } +/* Returns TRUE if there are no Require headers, otherwise returns FALSE + * and also returns a newly-allocated string of (comma-separated) unsupported + * options in the unsupported_reqs variable . + * + * There may be multiple Require headers, but we must send one single + * Unsupported header with all the unsupported options as response. If + * an incoming Require header contained a comma-separated list of options + * GstRtspConnection will already have split that list up into multiple + * headers. + * + * TODO: allow the application to decide what features are supported + */ +static gboolean +check_request_requirements (GstRTSPMessage * msg, gchar ** unsupported_reqs) +{ + GstRTSPResult res; + GPtrArray *arr = NULL; + gchar *reqs = NULL; + gint i; + + i = 0; + do { + res = gst_rtsp_message_get_header (msg, GST_RTSP_HDR_REQUIRE, &reqs, i++); + + if (res == GST_RTSP_ENOTIMPL) + break; + + if (arr == NULL) + arr = g_ptr_array_new_with_free_func ((GDestroyNotify) g_free); + + g_ptr_array_add (arr, g_strdup (reqs)); + } + while (TRUE); + + /* if we don't have any Require headers at all, all is fine */ + if (i == 1) + return TRUE; + + /* otherwise we've now processed at all the Require headers */ + g_ptr_array_add (arr, NULL); + + /* for now we don't commit to supporting anything, so will just report + * all of the required options as unsupported */ + *unsupported_reqs = g_strjoinv (", ", (gchar **) arr->pdata); + + g_ptr_array_unref (arr); + return FALSE; +} + static void handle_request (GstRTSPClient * client, GstRTSPMessage * request) { @@ -2181,6 +2249,7 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) GstRTSPSession *session = NULL; GstRTSPContext sctx = { NULL }, *ctx; GstRTSPMessage response = { 0 }; + gchar *unsupported_reqs = NULL; gchar *sessid; if (!(ctx = gst_rtsp_context_get_current ())) { @@ -2268,6 +2337,10 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request) if (!gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_URL)) goto not_authorized; + /* handle any 'Require' headers */ + if (!check_request_requirements (ctx->request, &unsupported_reqs)) + goto unsupported_requirement; + /* now see what is asked and dispatch to a dedicated handler */ switch (method) { case GST_RTSP_OPTIONS: @@ -2344,6 +2417,14 @@ not_authorized: /* error reply is already sent */ goto done; } +unsupported_requirement: + { + GST_ERROR ("client %p: Required option is not supported (%s)", client, + unsupported_reqs); + send_option_not_supported_response (client, ctx, unsupported_reqs); + g_free (unsupported_reqs); + goto done; + } not_implemented: { GST_ERROR ("client %p: method %d not implemented", client, method); -- cgit v1.2.3