From dd699397c20fac4b227bef94b59757f47b22bcc1 Mon Sep 17 00:00:00 2001 From: Andy Wingo Date: Wed, 15 Dec 2010 17:51:36 +0100 Subject: [PATCH] add gst_rtsp_url_decode_path_components * gst-libs/gst/rtsp/gstrtspurl.h: * gst-libs/gst/rtsp/gstrtspurl.c (gst_rtsp_url_decode_path_components): New public function, returns a strv of uri-decoded path components. * tests/check/Makefile.am: * tests/check/libs/rtsp.c: Add tests. --- gst-libs/gst/rtsp/gstrtspurl.c | 73 ++++++++++++++++ gst-libs/gst/rtsp/gstrtspurl.h | 2 + tests/check/Makefile.am | 8 ++ tests/check/libs/rtsp.c | 150 +++++++++++++++++++++++++++++++++ 4 files changed, 233 insertions(+) create mode 100644 tests/check/libs/rtsp.c diff --git a/gst-libs/gst/rtsp/gstrtspurl.c b/gst-libs/gst/rtsp/gstrtspurl.c index 0a71091cf7..6973e09c38 100644 --- a/gst-libs/gst/rtsp/gstrtspurl.c +++ b/gst-libs/gst/rtsp/gstrtspurl.c @@ -341,3 +341,76 @@ gst_rtsp_url_get_request_uri (const GstRTSPUrl * url) return uri; } + +static int +hex_to_int (gchar c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + else if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + else + return -1; +} + +static void +unescape_path_component (gchar * comp) +{ + guint len = strlen (comp); + guint i; + + for (i = 0; i + 2 < len; i++) + if (comp[i] == '%') { + int a, b; + + a = hex_to_int (comp[i + 1]); + b = hex_to_int (comp[i + 2]); + + /* The a||b check is to ensure that the byte is not '\0' */ + if (a >= 0 && b >= 0 && (a || b)) { + comp[i] = (gchar) (a * 16 + b); + memmove (comp + i + 1, comp + i + 3, len - i - 3); + len -= 2; + comp[len] = '\0'; + } + } +} + +/** + * gst_rtsp_url_decode_path_components: + * @url: a #GstRTSPUrl + * + * Splits the path of @url on '/' boundaries, decoding the resulting components, + * + * The decoding performed by this routine is "URI decoding", as defined in RFC + * 3986, commonly known as percent-decoding. For example, a string "foo%2fbar" + * will decode to "foo/bar" -- the %2f being replaced by the corresponding byte + * with hex value 0x2f. Note that there is no guarantee that the resulting byte + * sequence is valid in any given encoding. As a special case, %00 is not + * unescaped to NUL, as that would prematurely terminate the string. + * + * Also note that since paths usually start with a slash, the first component + * will usually be the empty string. + * + * Returns: a string vector. g_strfreev() after usage. + * + * Since: 0.10.32 + */ +gchar ** +gst_rtsp_url_decode_path_components (const GstRTSPUrl * url) +{ + gchar **ret; + guint i; + + g_return_val_if_fail (url != NULL, NULL); + g_return_val_if_fail (url->abspath != NULL, NULL); + + ret = g_strsplit (url->abspath, "/", -1); + + for (i = 0; ret[i]; i++) + unescape_path_component (ret[i]); + + return ret; +} diff --git a/gst-libs/gst/rtsp/gstrtspurl.h b/gst-libs/gst/rtsp/gstrtspurl.h index db9620ec7a..b34ee870fc 100644 --- a/gst-libs/gst/rtsp/gstrtspurl.h +++ b/gst-libs/gst/rtsp/gstrtspurl.h @@ -92,6 +92,8 @@ GstRTSPResult gst_rtsp_url_parse (const gchar *urlstr, GstRTSPUrl GstRTSPUrl* gst_rtsp_url_copy (const GstRTSPUrl *url); void gst_rtsp_url_free (GstRTSPUrl *url); gchar* gst_rtsp_url_get_request_uri (const GstRTSPUrl *url); +gchar** gst_rtsp_url_decode_path_components + (const GstRTSPUrl *url); GstRTSPResult gst_rtsp_url_set_port (GstRTSPUrl *url, guint16 port); GstRTSPResult gst_rtsp_url_get_port (const GstRTSPUrl *url, guint16 *port); diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index 03387af51f..31c9be1b4d 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -130,6 +130,7 @@ check_PROGRAMS = \ libs/pbutils \ libs/profile \ libs/rtp \ + libs/rtsp \ libs/tag \ libs/video \ $(check_orc) \ @@ -224,6 +225,13 @@ libs_rtp_LDADD = \ $(top_builddir)/gst-libs/gst/rtp/libgstrtp-@GST_MAJORMINOR@.la \ $(GST_BASE_LIBS) $(LDADD) +libs_rtsp_CFLAGS = \ + $(GST_PLUGINS_BASE_CFLAGS) \ + $(AM_CFLAGS) +libs_rtsp_LDADD = \ + $(top_builddir)/gst-libs/gst/rtsp/libgstrtsp-@GST_MAJORMINOR@.la \ + $(GST_BASE_LIBS) $(LDADD) + libs_tag_CFLAGS = \ $(GST_PLUGINS_BASE_CFLAGS) \ $(GST_BASE_CFLAGS) \ diff --git a/tests/check/libs/rtsp.c b/tests/check/libs/rtsp.c new file mode 100644 index 0000000000..fa26eead7a --- /dev/null +++ b/tests/check/libs/rtsp.c @@ -0,0 +1,150 @@ +/* GStreamer unit tests for the RTSP support library + * + * Copyright (C) 2010 Andy Wingo + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#include + +GST_START_TEST (test_rtsp_url_basic) +{ + GstRTSPUrl *url = NULL; + GstRTSPResult res; + + res = gst_rtsp_url_parse ("rtsp://localhost/foo/bar", &url); + fail_unless (res == GST_RTSP_OK); + fail_unless (url != NULL); + fail_unless (url->transports & GST_RTSP_LOWER_TRANS_TCP); + fail_unless (url->transports & GST_RTSP_LOWER_TRANS_UDP); + fail_unless (url->transports & GST_RTSP_LOWER_TRANS_UDP_MCAST); + fail_unless (url->family == GST_RTSP_FAM_INET); + fail_unless (!url->user); + fail_unless (!url->passwd); + fail_unless (!strcmp (url->host, "localhost")); + /* fail_unless (url->port == GST_RTSP_DEFAULT_PORT); */ + fail_unless (!strcmp (url->abspath, "/foo/bar")); + fail_unless (!url->query); + + gst_rtsp_url_free (url); +} + +GST_END_TEST; + +GST_START_TEST (test_rtsp_url_components_1) +{ + GstRTSPUrl *url = NULL; + GstRTSPResult res; + gchar **comps = NULL; + + res = gst_rtsp_url_parse ("rtsp://localhost/foo/bar", &url); + fail_unless (res == GST_RTSP_OK); + fail_unless (url != NULL); + + comps = gst_rtsp_url_decode_path_components (url); + fail_unless (comps != NULL); + fail_unless (g_strv_length (comps) == 3); + fail_unless (!strcmp (comps[0], "")); + fail_unless (!strcmp (comps[1], "foo")); + fail_unless (!strcmp (comps[2], "bar")); + + gst_rtsp_url_free (url); +} + +GST_END_TEST; + +GST_START_TEST (test_rtsp_url_components_2) +{ + GstRTSPUrl *url = NULL; + GstRTSPResult res; + gchar **comps = NULL; + + res = gst_rtsp_url_parse ("rtsp://localhost/foo%2Fbar/qux%20baz", &url); + fail_unless (res == GST_RTSP_OK); + fail_unless (url != NULL); + + comps = gst_rtsp_url_decode_path_components (url); + fail_unless (comps != NULL); + fail_unless (g_strv_length (comps) == 3); + fail_unless (!strcmp (comps[0], "")); + fail_unless (!strcmp (comps[1], "foo/bar")); + fail_unless (!strcmp (comps[2], "qux baz")); + + gst_rtsp_url_free (url); +} + +GST_END_TEST; + +GST_START_TEST (test_rtsp_url_components_3) +{ + GstRTSPUrl *url = NULL; + GstRTSPResult res; + gchar **comps = NULL; + + res = gst_rtsp_url_parse ("rtsp://localhost/foo%00bar/qux%20baz", &url); + fail_unless (res == GST_RTSP_OK); + fail_unless (url != NULL); + + comps = gst_rtsp_url_decode_path_components (url); + fail_unless (comps != NULL); + fail_unless (g_strv_length (comps) == 3); + fail_unless (!strcmp (comps[0], "")); + fail_unless (!strcmp (comps[1], "foo%00bar")); + fail_unless (!strcmp (comps[2], "qux baz")); + + gst_rtsp_url_free (url); +} + +GST_END_TEST; + +static Suite * +rtsp_suite (void) +{ + Suite *s = suite_create ("rtsp support library"); + TCase *tc_chain = tcase_create ("general"); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_rtsp_url_basic); + tcase_add_test (tc_chain, test_rtsp_url_components_1); + tcase_add_test (tc_chain, test_rtsp_url_components_2); + tcase_add_test (tc_chain, test_rtsp_url_components_3); + + return s; +} + +int +main (int argc, char **argv) +{ + int nf; + + Suite *s = rtsp_suite (); + SRunner *sr = srunner_create (s); + + gst_check_init (&argc, &argv); + + srunner_run_all (sr, CK_NORMAL); + nf = srunner_ntests_failed (sr); + srunner_free (sr); + + return nf; +}