diff options
author | Xavier Claessens <xavier.claessens@collabora.com> | 2015-08-11 16:10:59 -0400 |
---|---|---|
committer | Xavier Claessens <xavier.claessens@collabora.com> | 2015-08-12 11:34:27 -0400 |
commit | a3a835083ea678821ff9195c418cea3dd403709e (patch) | |
tree | 8bafc686f069feaeca877e34d9723f6dad960bbf | |
parent | e8586d2d871d1fbc942dc345315b33d3c7ce5a7a (diff) | |
download | libsoup-wip/xmlrpc-variant.tar.gz |
xmlrpc: Rework datetime APIwip/xmlrpc-variant
soup_xmlrpc_variant_new_datetime() now takes a SoupDate.
<datetime> is no longer parsed to a uint64 but into an opaque
type that must be parsed using soup_xmlrpc_variant_get_datetime().
-rw-r--r-- | docs/reference/libsoup-2.4-sections.txt | 1 | ||||
-rw-r--r-- | libsoup/libsoup-2.4.sym | 1 | ||||
-rw-r--r-- | libsoup/soup-xmlrpc.c | 101 | ||||
-rw-r--r-- | libsoup/soup-xmlrpc.h | 6 | ||||
-rw-r--r-- | tests/xmlrpc-server-test.c | 21 | ||||
-rw-r--r-- | tests/xmlrpc-test.c | 46 |
6 files changed, 135 insertions, 41 deletions
diff --git a/docs/reference/libsoup-2.4-sections.txt b/docs/reference/libsoup-2.4-sections.txt index 58f77e49..5185d0a3 100644 --- a/docs/reference/libsoup-2.4-sections.txt +++ b/docs/reference/libsoup-2.4-sections.txt @@ -839,6 +839,7 @@ soup_xmlrpc_build_request soup_xmlrpc_message_new soup_xmlrpc_parse_response soup_xmlrpc_variant_new_datetime +soup_xmlrpc_variant_get_datetime <SUBSECTION> SoupXMLRPCParams soup_xmlrpc_params_free diff --git a/libsoup/libsoup-2.4.sym b/libsoup/libsoup-2.4.sym index 257d4da5..e6ff89e8 100644 --- a/libsoup/libsoup-2.4.sym +++ b/libsoup/libsoup-2.4.sym @@ -563,4 +563,5 @@ soup_xmlrpc_parse_response soup_xmlrpc_request_new soup_xmlrpc_set_fault soup_xmlrpc_set_response +soup_xmlrpc_variant_get_datetime soup_xmlrpc_variant_new_datetime diff --git a/libsoup/soup-xmlrpc.c b/libsoup/soup-xmlrpc.c index 213bb84a..b1673d94 100644 --- a/libsoup/soup-xmlrpc.c +++ b/libsoup/soup-xmlrpc.c @@ -955,6 +955,13 @@ parse_base64 (xmlNode *typenode, GError **error) } static GVariant * +soup_xmlrpc_variant_new_custom (const char *type, const char *v) +{ + return g_variant_new ("(oss)", "/org/gnome/libsoup/ExtensionType", + type, v); +} + +static GVariant * parse_value (xmlNode *node, const char **signature, GError **error) { xmlNode *typenode; @@ -1043,25 +1050,15 @@ parse_value (xmlNode *node, const char **signature, GError **error) } variant = parse_array (typenode, signature, error); } else if (g_str_equal (typename, "dateTime.iso8601")) { - SoupDate *date; - - if (class != G_VARIANT_CLASS_VARIANT && - class != G_VARIANT_CLASS_INT64) { + if (class != G_VARIANT_CLASS_VARIANT) { g_set_error (error, SOUP_XMLRPC_ERROR, SOUP_XMLRPC_ERROR_ARGUMENTS, "<dateTime.iso8601> node does not match signature"); goto fail; } content = xmlNodeGetContent (typenode); - date = soup_date_new_from_string ((char *)content); - if (!date) { - g_set_error (error, SOUP_XMLRPC_ERROR, SOUP_XMLRPC_ERROR_ARGUMENTS, - "Couldn't parse date: %s", content); - goto fail; - } - - variant = g_variant_new_int64 (soup_date_to_time_t (date)); - soup_date_free (date); + variant = soup_xmlrpc_variant_new_custom ("dateTime.iso8601", + (const char *)content); } else { g_set_error (error, SOUP_XMLRPC_ERROR, SOUP_XMLRPC_ERROR_ARGUMENTS, "Unknown node name %s", typename); @@ -1143,7 +1140,11 @@ soup_xmlrpc_params_new (xmlNode *node) * another element type (e.g. "as") or could be a tuple (e.g. "(ss)"). * - <base64> will be deserialized to "ay". * - <string> will be deserialized to "s". - * - <dateTime.iso8601> will be deserialized to int64 unix timestamp. + * - <dateTime.iso8601> will be deserialized to an unspecified variant + * type. If @signature is provided it must have the generic "v" type, which + * means there is no guarantee that it's actually a datetime that has been + * received. soup_xmlrpc_variant_get_datetime() must be used to parse and + * type check this special variant. * - @signature must not have maybes, otherwise an error is returned. * - Dictionaries must have string keys, otherwise an error is returned. * @@ -1355,35 +1356,89 @@ fail: /** * soup_xmlrpc_variant_new_datetime: - * @timestamp: a unix timestamp + * @date: a #SoupDate * * Construct a special #GVariant used to serialize a <dateTime.iso8601> * node. See soup_xmlrpc_build_request(). * + * The actual type of the returned #GVariant is unspecified and "v" or "*" + * should be used in variant format strings. For example: + * <informalexample><programlisting> + * args = g_variant_new ("(v)", soup_xmlrpc_variant_new_datetime (date)); + * </programlisting></informalexample> + * * Returns: a floating #GVariant. * * Since: 2.52 */ GVariant * -soup_xmlrpc_variant_new_datetime (time_t timestamp) +soup_xmlrpc_variant_new_datetime (SoupDate *date) { - SoupDate *date; GVariant *variant; char *str; - date = soup_date_new_from_time_t (timestamp); str = soup_date_to_string (date, SOUP_DATE_ISO8601_XMLRPC); - variant = g_variant_new ("(oss)", - "/org/gnome/libsoup/ExtensionType", - "dateTime.iso8601", - str); - soup_date_free (date); + variant = soup_xmlrpc_variant_new_custom ("dateTime.iso8601", str); g_free (str); return variant; } /** + * soup_xmlrpc_variant_get_datetime: + * @variant: a #GVariant + * @error: a #GError, or %NULL + * + * Get the #SoupDate from special #GVariant created by + * soup_xmlrpc_variant_new_datetime() or by parsing a <dateTime.iso8601> + * node. See soup_xmlrpc_params_parse(). + * + * If @variant does not contain a datetime it will return an error but it is not + * considered a programmer error because it generally means parameters received + * are not in the expected type. + * + * Returns: a new #SoupDate, or %NULL on error. + * + * Since: 2.52 + */ +SoupDate * +soup_xmlrpc_variant_get_datetime (GVariant *variant, GError **error) +{ + SoupDate *date = NULL; + const char *path; + const char *type; + const char *v; + + if (!g_variant_is_of_type (variant, G_VARIANT_TYPE ("(oss)"))) { + g_set_error (error, SOUP_XMLRPC_ERROR, SOUP_XMLRPC_ERROR_ARGUMENTS, + "Variant is of type '%s' which is not expected for a datetime", + g_variant_get_type_string (variant)); + return NULL; + } + + g_variant_get (variant, "(&o&s&s)", &path, &type, &v); + + if (!g_str_equal (path, "/org/gnome/libsoup/ExtensionType") || + !g_str_equal (type, "dateTime.iso8601")) { + g_set_error (error, SOUP_XMLRPC_ERROR, SOUP_XMLRPC_ERROR_ARGUMENTS, + "Variant doesn't represent a datetime: %s", + g_variant_get_type_string (variant)); + return NULL; + } + + date = soup_date_new_from_string (v); + + if (date == NULL) { + g_set_error (error, SOUP_XMLRPC_ERROR, SOUP_XMLRPC_ERROR_ARGUMENTS, + "Can't parse datetime string: %s", v); + return NULL; + } + + return date; + +} + +/** * SOUP_XMLRPC_FAULT: * * A #GError domain representing an XML-RPC fault code. Used with diff --git a/libsoup/soup-xmlrpc.h b/libsoup/soup-xmlrpc.h index b51d1bd8..bed6c81b 100644 --- a/libsoup/soup-xmlrpc.h +++ b/libsoup/soup-xmlrpc.h @@ -58,7 +58,11 @@ void soup_xmlrpc_message_set_fault (SoupMessage *msg, /* Utils */ SOUP_AVAILABLE_IN_2_52 -GVariant *soup_xmlrpc_variant_new_datetime (time_t timestamp); +GVariant *soup_xmlrpc_variant_new_datetime (SoupDate *date); + +SOUP_AVAILABLE_IN_2_52 +SoupDate *soup_xmlrpc_variant_get_datetime (GVariant *variant, + GError **error); /* Errors */ #define SOUP_XMLRPC_ERROR soup_xmlrpc_error_quark() diff --git a/tests/xmlrpc-server-test.c b/tests/xmlrpc-server-test.c index 59d31971..db390cc5 100644 --- a/tests/xmlrpc-server-test.c +++ b/tests/xmlrpc-server-test.c @@ -119,17 +119,25 @@ static void do_dateChange (SoupMessage *msg, SoupXMLRPCParams *params) { GVariant *args; - time_t timestamp; + GVariant *timestamp; SoupDate *date; GVariant *arg; int val; + GError *error = NULL; - if (!(args = parse_params (msg, params, "(xa{si})"))) + if (!(args = parse_params (msg, params, "(va{si})"))) return; - g_variant_get (args, "(x@a{si})", ×tamp, &arg); + g_variant_get (args, "(v@a{si})", ×tamp, &arg); - date = soup_date_new_from_time_t (timestamp); + date = soup_xmlrpc_variant_get_datetime (timestamp, &error); + if (!date) { + soup_xmlrpc_message_set_fault (msg, + SOUP_XMLRPC_FAULT_SERVER_ERROR_INVALID_METHOD_PARAMETERS, + "%s", error->message); + g_clear_error (&error); + goto fail; + } if (g_variant_lookup (arg, "tm_year", "i", &val)) date->year = val + 1900; @@ -145,12 +153,15 @@ do_dateChange (SoupMessage *msg, SoupXMLRPCParams *params) date->second = val; soup_xmlrpc_message_set_response (msg, - soup_xmlrpc_variant_new_datetime (soup_date_to_time_t (date)), + soup_xmlrpc_variant_new_datetime (date), NULL); soup_date_free (date); + +fail: g_variant_unref (args); g_variant_unref (arg); + g_variant_unref (timestamp); } static void diff --git a/tests/xmlrpc-test.c b/tests/xmlrpc-test.c index b9660721..c50995aa 100644 --- a/tests/xmlrpc-test.c +++ b/tests/xmlrpc-test.c @@ -202,10 +202,11 @@ static void test_dateChange (void) { GVariantDict structval; - SoupDate *date; - time_t timestamp; + SoupDate *date, *result; + char *timestamp; GVariant *retval; gboolean ok; + GError *error = NULL; SOUP_TEST_SKIP_IF_NO_XMLRPC_SERVER; @@ -266,22 +267,36 @@ test_dateChange (void) "i", date->second); } - timestamp = soup_date_to_time_t (date); - soup_date_free (date); - debug_printf (2, "} -> "); ok = do_xmlrpc ("dateChange", g_variant_new ("(vv)", - soup_xmlrpc_variant_new_datetime (timestamp), + soup_xmlrpc_variant_new_datetime (date), g_variant_dict_end (&structval)), - "x", &retval); - if (!ok) + NULL, &retval); + if (!ok) { + soup_date_free (date); return; + } - debug_printf (2, "%"G_GINT64_FORMAT"\n", g_variant_get_int64 (retval)); + result = soup_xmlrpc_variant_get_datetime (retval, &error); + g_assert_no_error (error); - g_assert_cmpint (timestamp, ==, g_variant_get_int64 (retval)); + if (debug_level >= 2) { + timestamp = soup_date_to_string (result, SOUP_DATE_ISO8601_XMLRPC); + debug_printf (2, "%s\n", timestamp); + g_free (timestamp); + } + + g_assert_cmpint (date->year, ==, result->year); + g_assert_cmpint (date->month, ==, result->month); + g_assert_cmpint (date->day, ==, result->day); + g_assert_cmpint (date->hour, ==, result->hour); + g_assert_cmpint (date->minute, ==, result->minute); + g_assert_cmpint (date->second, ==, result->second); + + soup_date_free (date); + soup_date_free (result); g_variant_unref (retval); } @@ -474,6 +489,8 @@ verify_serialization_fail (GVariant *value) static void test_serializer (void) { + SoupDate *date; + verify_serialization (g_variant_new_parsed ("()"), "<params/>"); verify_serialization (g_variant_new_parsed ("(1, 2)"), @@ -503,10 +520,12 @@ test_serializer (void) "<params>" "<param><value><int>42</int></value></param>" "</params>"); - verify_serialization (g_variant_new ("(@*)", soup_xmlrpc_variant_new_datetime (1434161309)), + date = soup_date_new_from_time_t (1434161309); + verify_serialization (g_variant_new ("(v)", soup_xmlrpc_variant_new_datetime (date)), "<params>" "<param><value><dateTime.iso8601>20150613T02:08:29</dateTime.iso8601></value></param>" "</params>"); + soup_date_free (date); verify_serialization (g_variant_new ("(s)", "<>&"), "<params>" "<param><value><string><>&</string></value></param>" @@ -590,6 +609,7 @@ static void test_deserializer (void) { char *tmp; + SoupDate *date; verify_deserialization (g_variant_new_parsed ("@av []"), NULL, @@ -615,11 +635,13 @@ test_deserializer (void) "<member><name>one</name><value><int>1</int></value></member>" "<member><name>two</name><value><int>2</int></value></member>" "</struct></value></param></params>"); - verify_deserialization (g_variant_new_parsed ("[<int64 1434146909>]"), + date = soup_date_new_from_time_t (1434146909); + verify_deserialization (g_variant_new_parsed ("[%v]", soup_xmlrpc_variant_new_datetime (date)), NULL, "<params>" "<param><value><dateTime.iso8601>20150612T22:08:29</dateTime.iso8601></value></param>" "</params>"); + soup_date_free (date); verify_deserialization (g_variant_new_parsed ("[<b'bytestring'>]"), NULL, "<params>" |