[libgdata] Bug 653535 — Let GDataAuthorizer re-process request after refreshing



commit 5494aef7d705b9a4ad2d0da7db6dd6c0a43f9560
Author: Philip Withnall <philip tecnocode co uk>
Date:   Wed Jun 29 08:56:02 2011 +0100

    Bug 653535 â Let GDataAuthorizer re-process request after refreshing
    
    After receiving a 401 status (unauthorised) from the server and refreshing
    the current GDataAuthorizer, re-process the message in question with the
    authoriser before re-sending it, so that it has updated credentials set on
    it.
    
    This involves a slight change in the semantics of
    GDataAuthorizer->process_request, which now has to handle being called
    multiple times on a given message.
    
    Closes: bgo#653535

 gdata/gdata-authorizer.h              |    3 ++-
 gdata/gdata-client-login-authorizer.c |    2 +-
 gdata/gdata-oauth1-authorizer.c       |    2 +-
 gdata/gdata-service.c                 |   17 ++++++++++++++++-
 4 files changed, 20 insertions(+), 4 deletions(-)
---
diff --git a/gdata/gdata-authorizer.h b/gdata/gdata-authorizer.h
index 5898348..3df0da0 100644
--- a/gdata/gdata-authorizer.h
+++ b/gdata/gdata-authorizer.h
@@ -48,7 +48,8 @@ typedef struct _GDataAuthorizer		GDataAuthorizer; /* dummy typedef */
  * GDataAuthorizerInterface:
  * @parent: the parent type
  * @process_request: a function to append authorization headers to queries before they are submitted to the online service under the given
- * authorization domain (which may be %NULL); this must be implemented and must be thread safe
+ * authorization domain (which may be %NULL); this must be implemented and must be thread safe, and must also handle being called multiple times on
+ * the same #SoupMessage instance (so must be careful to replace headers rather than append them, for example)
  * @is_authorized_for_domain: a function to check whether the authorizer is authorized against the given domain; this must be implemented and must
  * be thread safe
  * @refresh_authorization: (allow-none): a function to force a refresh of any authorization tokens the authorizer holds, returning %TRUE if a refresh
diff --git a/gdata/gdata-client-login-authorizer.c b/gdata/gdata-client-login-authorizer.c
index ab7f66c..ce50522 100644
--- a/gdata/gdata-client-login-authorizer.c
+++ b/gdata/gdata-client-login-authorizer.c
@@ -401,7 +401,7 @@ process_request (GDataAuthorizer *self, GDataAuthorizationDomain *domain, SoupMe
 			g_warning ("Not authorizing a non-HTTPS message with the user's ClientLogin auth token as the connection isn't secure.");
 		} else {
 			gchar *authorisation_header = g_strdup_printf ("GoogleLogin auth=%s", auth_token);
-			soup_message_headers_append (message->request_headers, "Authorization", authorisation_header);
+			soup_message_headers_replace (message->request_headers, "Authorization", authorisation_header);
 			g_free (authorisation_header);
 		}
 	}
diff --git a/gdata/gdata-oauth1-authorizer.c b/gdata/gdata-oauth1-authorizer.c
index 0b635dc..bce48b7 100644
--- a/gdata/gdata-oauth1-authorizer.c
+++ b/gdata/gdata-oauth1-authorizer.c
@@ -558,7 +558,7 @@ sign_message (GDataOAuth1Authorizer *self, SoupMessage *message, const gchar *to
 	g_string_append_uri_escaped (authorization_header, nonce, NULL, FALSE);
 	g_string_append (authorization_header, "\",oauth_version=\"1.0\"");
 
-	soup_message_headers_append (message->request_headers, "Authorization", authorization_header->str);
+	soup_message_headers_replace (message->request_headers, "Authorization", authorization_header->str);
 
 	g_string_free (authorization_header, TRUE);
 	free (signature);
diff --git a/gdata/gdata-service.c b/gdata/gdata-service.c
index 848914c..74c0e21 100644
--- a/gdata/gdata-service.c
+++ b/gdata/gdata-service.c
@@ -284,6 +284,10 @@ real_append_query_headers (GDataService *self, GDataAuthorizationDomain *domain,
 	/* Set the authorisation header */
 	if (self->priv->authorizer != NULL) {
 		gdata_authorizer_process_request (self->priv->authorizer, domain, message);
+
+		/* Store the authorisation domain on the message so that we can access it again after refreshing authorisation if necessary.
+		 * See _gdata_service_send_message(). */
+		g_object_set_data_full (G_OBJECT (message), "gdata-authorization-domain", g_object_ref (domain), (GDestroyNotify) g_object_unref);
 	}
 
 	/* Set the GData-Version header to tell it we want to use the v2 API */
@@ -680,11 +684,22 @@ _gdata_service_send_message (GDataService *self, SoupMessage *message, GCancella
 	}
 
 	/* Not authorised, or authorisation has expired. If we were authorised in the first place, attempt to refresh the authorisation and
-	 * try sending the message again (but only once, so we don't get caught in an infinite loop of denied authorisation errors). */
+	 * try sending the message again (but only once, so we don't get caught in an infinite loop of denied authorisation errors).
+	 *
+	 * Note that we have to re-process the message with the authoriser so that its authorisation headers get updated after the refresh
+	 * (bgo#653535). */
 	if (message->status_code == SOUP_STATUS_UNAUTHORIZED) {
 		GDataAuthorizer *authorizer = self->priv->authorizer;
 
 		if (authorizer != NULL && gdata_authorizer_refresh_authorization (authorizer, cancellable, NULL) == TRUE) {
+			GDataAuthorizationDomain *domain;
+
+			/* Re-process the request */
+			domain = g_object_get_data (G_OBJECT (message), "gdata-authorization-domain");
+			g_assert (domain == NULL || GDATA_IS_AUTHORIZATION_DOMAIN (domain));
+
+			gdata_authorizer_process_request (authorizer, domain, message);
+
 			/* Send the message again */
 			g_clear_error (error);
 			_gdata_service_actually_send_message (self->priv->session, message, cancellable, error);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]