summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Claessens <xavier.claessens@collabora.com>2015-08-11 16:10:59 -0400
committerXavier Claessens <xavier.claessens@collabora.com>2015-08-12 11:34:27 -0400
commita3a835083ea678821ff9195c418cea3dd403709e (patch)
tree8bafc686f069feaeca877e34d9723f6dad960bbf
parente8586d2d871d1fbc942dc345315b33d3c7ce5a7a (diff)
downloadlibsoup-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.txt1
-rw-r--r--libsoup/libsoup-2.4.sym1
-rw-r--r--libsoup/soup-xmlrpc.c101
-rw-r--r--libsoup/soup-xmlrpc.h6
-rw-r--r--tests/xmlrpc-server-test.c21
-rw-r--r--tests/xmlrpc-test.c46
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)").
* - &lt;base64&gt; will be deserialized to "ay".
* - &lt;string&gt; will be deserialized to "s".
- * - &lt;dateTime.iso8601&gt; will be deserialized to int64 unix timestamp.
+ * - &lt;dateTime.iso8601&gt; 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 &lt;dateTime.iso8601&gt;
* 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 &lt;dateTime.iso8601&gt;
+ * 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})", &timestamp, &arg);
+ g_variant_get (args, "(v@a{si})", &timestamp, &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>&lt;&gt;&amp;</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>"