[gupnp] ServiceProxy: Parse response in call_finish
- From: Jens Georg <jensgeorg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gupnp] ServiceProxy: Parse response in call_finish
- Date: Sat, 2 Apr 2022 08:38:47 +0000 (UTC)
commit 291aa2e9051e8e653bbf6489f70dfee753593311
Author: Jens Georg <mail jensge org>
Date: Sat Apr 2 10:32:49 2022 +0200
ServiceProxy: Parse response in call_finish
So that all errors that are not related to getting parameters are
handled when call_finish is called, including SOAP errors.
This removes the weird necessity to call _get on actions to get the SOAP
errors.
libgupnp/gupnp-service-proxy-action-private.h | 6 +
libgupnp/gupnp-service-proxy-action.c | 316 +++++++++++++-------------
libgupnp/gupnp-service-proxy.c | 20 +-
3 files changed, 175 insertions(+), 167 deletions(-)
---
diff --git a/libgupnp/gupnp-service-proxy-action-private.h b/libgupnp/gupnp-service-proxy-action-private.h
index 4bd1015..3f92e51 100644
--- a/libgupnp/gupnp-service-proxy-action-private.h
+++ b/libgupnp/gupnp-service-proxy-action-private.h
@@ -10,6 +10,7 @@
#define GUPNP_SERVICE_PROXY_ACTION_H
#include <gobject/gvaluecollector.h>
+#include <libxml/tree.h>
G_BEGIN_DECLS
@@ -148,6 +149,8 @@ struct _GUPnPServiceProxyAction {
GPtrArray *args;
GHashTable *arg_map;
gboolean pending;
+ xmlDocPtr doc;
+ xmlNodePtr params;
};
G_GNUC_INTERNAL GUPnPServiceProxyAction *
@@ -161,6 +164,9 @@ gupnp_service_proxy_action_get_result_valist (GUPnPServiceProxyAction *action,
G_GNUC_INTERNAL void
gupnp_service_proxy_action_serialize (GUPnPServiceProxyAction *action,
const char *service_type);
+
+G_GNUC_INTERNAL void
+gupnp_service_proxy_action_check_response (GUPnPServiceProxyAction *action);
G_END_DECLS
#endif /* GUPNP_SERVICE_PROXY_ACTION_H */
diff --git a/libgupnp/gupnp-service-proxy-action.c b/libgupnp/gupnp-service-proxy-action.c
index a4f151f..ca148c8 100644
--- a/libgupnp/gupnp-service-proxy-action.c
+++ b/libgupnp/gupnp-service-proxy-action.c
@@ -54,151 +54,6 @@ read_out_parameter (const char *arg_name,
}
-/* Checks an action response for errors and returns the parsed
- * xmlDoc object. */
-static xmlDoc *
-check_action_response (G_GNUC_UNUSED GUPnPServiceProxy *proxy,
- GUPnPServiceProxyAction *action,
- xmlNode **params,
- GError **error)
-{
- xmlDoc *response;
- int code;
-
- if (action->msg == NULL || action->response == NULL) {
- g_set_error (error,
- GUPNP_SERVER_ERROR,
- GUPNP_SERVER_ERROR_INVALID_RESPONSE,
- "No message, the action was not sent?");
-
- return NULL;
- }
-
- SoupStatus status = soup_message_get_status (action->msg);
-
- /* Check for errors */
- switch (status) {
- case SOUP_STATUS_OK:
- case SOUP_STATUS_INTERNAL_SERVER_ERROR:
- break;
- default:
- _gupnp_error_set_server_error (error, action->msg);
-
- return NULL;
- }
-
- /* Parse response */
- gconstpointer data;
- gsize length;
- data = g_bytes_get_data (action->response, &length);
- response = xmlRecoverMemory (data, length);
- g_clear_pointer (&action->response, g_bytes_unref);
-
- if (!response) {
- if (status == SOUP_STATUS_OK) {
- g_set_error (error,
- GUPNP_SERVER_ERROR,
- GUPNP_SERVER_ERROR_INVALID_RESPONSE,
- "Could not parse SOAP response");
- } else {
- g_set_error_literal (
- error,
- GUPNP_SERVER_ERROR,
- GUPNP_SERVER_ERROR_INTERNAL_SERVER_ERROR,
- soup_message_get_reason_phrase (action->msg));
- }
-
- return NULL;
- }
-
- /* Get parameter list */
- *params = xml_util_get_element ((xmlNode *) response,
- "Envelope",
- NULL);
- if (*params != NULL)
- *params = xml_util_real_node ((*params)->children);
-
- if (*params != NULL) {
- if (strcmp ((const char *) (*params)->name, "Header") == 0)
- *params = xml_util_real_node ((*params)->next);
-
- if (*params != NULL)
- if (strcmp ((const char *) (*params)->name, "Body") != 0)
- *params = NULL;
- }
-
- if (*params != NULL)
- *params = xml_util_real_node ((*params)->children);
-
- if (*params == NULL) {
- g_set_error (error,
- GUPNP_SERVER_ERROR,
- GUPNP_SERVER_ERROR_INVALID_RESPONSE,
- "Invalid Envelope");
-
- xmlFreeDoc (response);
-
- return NULL;
- }
-
- /* Check whether we have a Fault */
- if (status == SOUP_STATUS_INTERNAL_SERVER_ERROR) {
- xmlNode *param;
- char *desc;
-
- param = xml_util_get_element (*params,
- "detail",
- "UPnPError",
- NULL);
-
- if (!param) {
- g_set_error (error,
- GUPNP_SERVER_ERROR,
- GUPNP_SERVER_ERROR_INVALID_RESPONSE,
- "Invalid Fault");
-
- xmlFreeDoc (response);
-
- return NULL;
- }
-
- /* Code */
- code = xml_util_get_child_element_content_int
- (param, "errorCode");
- if (code == -1) {
- g_set_error (error,
- GUPNP_SERVER_ERROR,
- GUPNP_SERVER_ERROR_INVALID_RESPONSE,
- "Invalid Fault");
-
- xmlFreeDoc (response);
-
- return NULL;
- }
-
- /* Description */
- desc = xml_util_get_child_element_content_glib
- (param, "errorDescription");
- if (desc == NULL)
- desc = g_strdup (
- soup_message_get_reason_phrase (action->msg));
-
- g_set_error_literal (error,
- GUPNP_CONTROL_ERROR,
- code,
- desc);
-
- g_free (desc);
-
- xmlFreeDoc (response);
-
- return NULL;
- }
-
- return response;
-}
-
-
GUPnPServiceProxyAction *
gupnp_service_proxy_action_new_internal (const char *action) {
GUPnPServiceProxyAction *ret;
@@ -244,6 +99,7 @@ action_dispose (GUPnPServiceProxyAction *action)
g_hash_table_destroy (action->arg_map);
g_ptr_array_unref (action->args);
g_clear_pointer (&action->response, g_bytes_unref);
+ g_clear_pointer (&action->doc, xmlFreeDoc);
g_free (action->name);
}
@@ -494,6 +350,151 @@ gupnp_service_proxy_action_serialize (GUPnPServiceProxyAction *action,
g_string_insert (action->msg_str, action->header_pos, "\">");
}
+/* Checks an action response for errors and returns the parsed
+ * xmlDoc object. */
+void
+gupnp_service_proxy_action_check_response (GUPnPServiceProxyAction *action)
+{
+ xmlDoc *response;
+ int code;
+
+ if (action->doc != NULL) {
+ return;
+ }
+
+ if (action->error != NULL) {
+ return;
+ }
+
+ if (action->msg == NULL || action->response == NULL) {
+ g_set_error_literal (&action->error,
+ GUPNP_SERVER_ERROR,
+ GUPNP_SERVER_ERROR_INVALID_RESPONSE,
+ "No message, the action was not sent?");
+
+ return;
+ }
+
+ SoupStatus status = soup_message_get_status (action->msg);
+
+ if (status != SOUP_STATUS_OK &&
+ status != SOUP_STATUS_INTERNAL_SERVER_ERROR) {
+ _gupnp_error_set_server_error (&action->error, action->msg);
+ return;
+ }
+
+ /* Parse response */
+ gconstpointer data;
+ gsize length;
+ data = g_bytes_get_data (action->response, &length);
+ response = xmlRecoverMemory (data, length);
+ g_clear_pointer (&action->response, g_bytes_unref);
+
+ if (!response) {
+ if (status == SOUP_STATUS_OK) {
+ g_set_error_literal (
+ &action->error,
+ GUPNP_SERVER_ERROR,
+ GUPNP_SERVER_ERROR_INVALID_RESPONSE,
+ "Could not parse SOAP response");
+ } else {
+ g_set_error_literal (
+ &action->error,
+ GUPNP_SERVER_ERROR,
+ GUPNP_SERVER_ERROR_INTERNAL_SERVER_ERROR,
+ soup_message_get_reason_phrase (action->msg));
+ }
+
+ return;
+ }
+
+ xmlNodePtr params = NULL;
+ /* Get parameter list */
+ params = xml_util_get_element ((xmlNode *) response, "Envelope", NULL);
+ if (params != NULL)
+ params = xml_util_real_node (params->children);
+
+ if (params != NULL) {
+ if (strcmp ((const char *) params->name, "Header") == 0)
+ params = xml_util_real_node (params->next);
+
+ if (params != NULL)
+ if (strcmp ((const char *) params->name, "Body") != 0)
+ params = NULL;
+ }
+
+ if (params != NULL)
+ params = xml_util_real_node (params->children);
+
+ if (params == NULL) {
+ g_set_error (&action->error,
+ GUPNP_SERVER_ERROR,
+ GUPNP_SERVER_ERROR_INVALID_RESPONSE,
+ "Invalid Envelope");
+
+ xmlFreeDoc (response);
+
+ return;
+ }
+
+ /* Check whether we have a Fault */
+ if (status == SOUP_STATUS_INTERNAL_SERVER_ERROR) {
+ xmlNode *param;
+ char *desc;
+
+ param = xml_util_get_element (params,
+ "detail",
+ "UPnPError",
+ NULL);
+
+ if (!param) {
+ g_set_error (&action->error,
+ GUPNP_SERVER_ERROR,
+ GUPNP_SERVER_ERROR_INVALID_RESPONSE,
+ "Invalid Fault");
+
+ xmlFreeDoc (response);
+
+ return;
+ }
+
+ /* Code */
+ code = xml_util_get_child_element_content_int (param,
+ "errorCode");
+ if (code == -1) {
+ g_set_error (&action->error,
+ GUPNP_SERVER_ERROR,
+ GUPNP_SERVER_ERROR_INVALID_RESPONSE,
+ "Invalid Fault");
+
+ xmlFreeDoc (response);
+
+ return;
+ }
+
+ /* Description */
+ desc = xml_util_get_child_element_content_glib (
+ param,
+ "errorDescription");
+ if (desc == NULL)
+ desc = g_strdup (
+ soup_message_get_reason_phrase (action->msg));
+
+ g_set_error_literal (&action->error,
+ GUPNP_CONTROL_ERROR,
+ code,
+ desc);
+
+ g_free (desc);
+
+ xmlFreeDoc (response);
+
+ return;
+ }
+
+ action->doc = response;
+}
+
/**
* gupnp_service_proxy_action_get_result_list:
* @action: A #GUPnPServiceProxyAction handle
@@ -568,8 +569,6 @@ gupnp_service_proxy_action_get_result_list (GUPnPServiceProxyAction *action,
GList **out_values,
GError **error)
{
- xmlDoc *response;
- xmlNode *params;
GList *names;
GList *types;
GList *out_values_list;
@@ -586,8 +585,8 @@ gupnp_service_proxy_action_get_result_list (GUPnPServiceProxyAction *action,
}
/* Check response for errors and do initial parsing */
- response = check_action_response (NULL, action, ¶ms, &action->error);
- if (response == NULL) {
+ gupnp_service_proxy_action_check_response (action);
+ if (action->error != NULL) {
g_propagate_error (error, g_error_copy (action->error));
return FALSE;
@@ -601,7 +600,7 @@ gupnp_service_proxy_action_get_result_list (GUPnPServiceProxyAction *action,
val = g_new0 (GValue, 1);
g_value_init (val, (GType) types->data);
- read_out_parameter (names->data, val, params);
+ read_out_parameter (names->data, val, action->params);
out_values_list = g_list_append (out_values_list, val);
@@ -610,9 +609,6 @@ gupnp_service_proxy_action_get_result_list (GUPnPServiceProxyAction *action,
*out_values = out_values_list;
- /* Cleanup */
- xmlFreeDoc (response);
-
return TRUE;
}
@@ -679,9 +675,6 @@ gupnp_service_proxy_action_get_result_hash (GUPnPServiceProxyAction *action,
GHashTable *hash,
GError **error)
{
- xmlDoc *response;
- xmlNode *params;
-
g_return_val_if_fail (action, FALSE);
/* Check for saved error from begin_action() */
@@ -692,18 +685,17 @@ gupnp_service_proxy_action_get_result_hash (GUPnPServiceProxyAction *action,
}
/* Check response for errors and do initial parsing */
- response = check_action_response (NULL, action, ¶ms, &action->error);
- if (response == NULL) {
+ gupnp_service_proxy_action_check_response (action);
+ if (action->error != NULL) {
g_propagate_error (error, g_error_copy (action->error));
return FALSE;
}
/* Read arguments */
- g_hash_table_foreach (hash, (GHFunc) read_out_parameter, params);
-
- /* Cleanup */
- xmlFreeDoc (response);
+ g_hash_table_foreach (hash,
+ (GHFunc) read_out_parameter,
+ action->params);
return TRUE;
diff --git a/libgupnp/gupnp-service-proxy.c b/libgupnp/gupnp-service-proxy.c
index 60b290e..3c08c93 100644
--- a/libgupnp/gupnp-service-proxy.c
+++ b/libgupnp/gupnp-service-proxy.c
@@ -14,14 +14,16 @@
#include <locale.h>
#include <errno.h>
-#include "gupnp-service-proxy.h"
-#include "gupnp-service-proxy-action-private.h"
+#include "gena-protocol.h"
#include "gupnp-context-private.h"
+#include "gupnp-error-private.h"
#include "gupnp-error.h"
+#include "gupnp-service-proxy.h"
+#include "gupnp-service-proxy-action-private.h"
#include "gupnp-types.h"
-#include "gena-protocol.h"
-#include "http-headers.h"
#include "gvalue-util.h"
+#include "http-headers.h"
+#include "xml-util.h"
struct _GUPnPServiceProxyPrivate {
gboolean subscribed;
@@ -466,7 +468,15 @@ action_task_got_response (GObject *source,
break;
default:
- g_task_return_pointer (task, g_task_get_task_data (task), NULL);
+ gupnp_service_proxy_action_check_response (action);
+ if (action->error != NULL) {
+ g_task_return_error (task,
+ g_error_copy (action->error));
+ } else {
+ g_task_return_pointer (task,
+ g_task_get_task_data (task),
+ NULL);
+ }
g_object_unref (task);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]