simplify auditor_api_handle.c, do not modify global context with respect to 'Expect' header

This commit is contained in:
Christian Grothoff 2022-03-19 15:25:43 +01:00
parent f5e5f4b843
commit 685837ad28
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
3 changed files with 77 additions and 147 deletions

View File

@ -359,6 +359,10 @@ TALER_AUDITOR_deposit_confirmation (
dh->ctx.headers, dh->ctx.headers,
&handle_deposit_confirmation_finished, &handle_deposit_confirmation_finished,
dh); dh);
/* Disable 100 continue processing */
GNUNET_CURL_extend_headers (dh->job,
curl_slist_append (NULL,
"Expect:"));
return dh; return dh;
} }

View File

@ -193,17 +193,6 @@ handle_exchanges_finished (void *cls,
} }
/**
* Submit an /exchanges request to the auditor and get the
* auditor's response. If the auditor's reply is not
* well-formed, we return an HTTP status code of zero to @a cb.
*
* @param auditor the auditor handle; the auditor must be ready to operate
* @param cb the callback to call when a reply for this request is available
* @param cb_cls closure for the above callback
* @return a handle for this request; NULL if the inputs are invalid (i.e.
* signatures fail to verify). In this case, the callback is not called.
*/
struct TALER_AUDITOR_ListExchangesHandle * struct TALER_AUDITOR_ListExchangesHandle *
TALER_AUDITOR_list_exchanges (struct TALER_AUDITOR_Handle *auditor, TALER_AUDITOR_list_exchanges (struct TALER_AUDITOR_Handle *auditor,
TALER_AUDITOR_ListExchangesResultCallback cb, TALER_AUDITOR_ListExchangesResultCallback cb,
@ -247,12 +236,6 @@ TALER_AUDITOR_list_exchanges (struct TALER_AUDITOR_Handle *auditor,
} }
/**
* Cancel a list exchanges request. This function cannot be used
* on a request handle if a response is already served for it.
*
* @param leh the list exchanges request handle
*/
void void
TALER_AUDITOR_list_exchanges_cancel ( TALER_AUDITOR_list_exchanges_cancel (
struct TALER_AUDITOR_ListExchangesHandle *leh) struct TALER_AUDITOR_ListExchangesHandle *leh)

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2014-2020 Taler Systems SA Copyright (C) 2014-2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software terms of the GNU General Public License as published by the Free Software
@ -75,12 +75,6 @@ enum AuditorHandleState
}; };
/**
* Data for the request to get the /version of a auditor.
*/
struct VersionRequest;
/** /**
* Handle to the auditor * Handle to the auditor
*/ */
@ -111,7 +105,12 @@ struct TALER_AUDITOR_Handle
* Data for the request to get the /version of a auditor, * Data for the request to get the /version of a auditor,
* NULL once we are past stage #MHS_INIT. * NULL once we are past stage #MHS_INIT.
*/ */
struct VersionRequest *vr; struct GNUNET_CURL_Job *vr;
/**
* The url for the @e vr job.
*/
char *vr_url;
/** /**
* Task for retrying /version request. * Task for retrying /version request.
@ -144,50 +143,12 @@ struct TALER_AUDITOR_Handle
/* ***************** Internal /version fetching ************* */ /* ***************** Internal /version fetching ************* */
/**
* Data for the request to get the /version of a auditor.
*/
struct VersionRequest
{
/**
* The connection to auditor this request handle will use
*/
struct TALER_AUDITOR_Handle *auditor;
/**
* The url for this handle
*/
char *url;
/**
* Entry for this request with the `struct GNUNET_CURL_Context`.
*/
struct GNUNET_CURL_Job *job;
};
/**
* Release memory occupied by a version request.
* Note that this does not cancel the request
* itself.
*
* @param vr request to free
*/
static void
free_version_request (struct VersionRequest *vr)
{
GNUNET_free (vr->url);
GNUNET_free (vr);
}
/** /**
* Decode the JSON in @a resp_obj from the /version response and store the data * Decode the JSON in @a resp_obj from the /version response and store the data
* in the @a key_data. * in the @a key_data.
* *
* @param[in] resp_obj JSON object to parse * @param[in] resp_obj JSON object to parse
* @param[out] auditor where to store the results we decoded * @param[in,out] auditor where to store the results we decoded
* @param[out] vc where to store version compatibility data * @param[out] vc where to store version compatibility data
* @return #TALER_EC_NONE on success * @return #TALER_EC_NONE on success
*/ */
@ -200,6 +161,7 @@ decode_version_json (const json_t *resp_obj,
unsigned int age; unsigned int age;
unsigned int revision; unsigned int revision;
unsigned int current; unsigned int current;
char dummy;
const char *ver; const char *ver;
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_string ("version", GNUNET_JSON_spec_string ("version",
@ -224,14 +186,16 @@ decode_version_json (const json_t *resp_obj,
return TALER_EC_GENERIC_JSON_INVALID; return TALER_EC_GENERIC_JSON_INVALID;
} }
if (3 != sscanf (ver, if (3 != sscanf (ver,
"%u:%u:%u", "%u:%u:%u%c",
&current, &current,
&revision, &revision,
&age)) &age,
&dummy))
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
return TALER_EC_GENERIC_VERSION_MALFORMED; return TALER_EC_GENERIC_VERSION_MALFORMED;
} }
GNUNET_free (auditor->version);
auditor->version = GNUNET_strdup (ver); auditor->version = GNUNET_strdup (ver);
vi->version = auditor->version; vi->version = auditor->version;
*vc = TALER_AUDITOR_VC_MATCH; *vc = TALER_AUDITOR_VC_MATCH;
@ -264,7 +228,7 @@ request_version (void *cls);
* Callback used when downloading the reply to a /version request * Callback used when downloading the reply to a /version request
* is complete. * is complete.
* *
* @param cls the `struct VersionRequest` * @param cls the `struct TALER_AUDITOR_Handle`
* @param response_code HTTP response code, 0 on error * @param response_code HTTP response code, 0 on error
* @param gresp_obj parsed JSON result, NULL on error, must be a `const json_t *` * @param gresp_obj parsed JSON result, NULL on error, must be a `const json_t *`
*/ */
@ -273,21 +237,19 @@ version_completed_cb (void *cls,
long response_code, long response_code,
const void *gresp_obj) const void *gresp_obj)
{ {
struct TALER_AUDITOR_Handle *auditor = cls;
const json_t *resp_obj = gresp_obj; const json_t *resp_obj = gresp_obj;
struct VersionRequest *vr = cls;
struct TALER_AUDITOR_Handle *auditor = vr->auditor;
enum TALER_AUDITOR_VersionCompatibility vc; enum TALER_AUDITOR_VersionCompatibility vc;
struct TALER_AUDITOR_HttpResponse hr = { struct TALER_AUDITOR_HttpResponse hr = {
.reply = resp_obj, .reply = resp_obj,
.http_status = (unsigned int) response_code .http_status = (unsigned int) response_code
}; };
auditor->vr = NULL;
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Received version from URL `%s' with status %ld.\n", "Received version from URL `%s' with status %ld.\n",
vr->url, auditor->url,
response_code); response_code);
free_version_request (vr);
auditor->vr = NULL;
vc = TALER_AUDITOR_VC_PROTOCOL_ERROR; vc = TALER_AUDITOR_VC_PROTOCOL_ERROR;
switch (response_code) switch (response_code)
{ {
@ -357,6 +319,43 @@ version_completed_cb (void *cls,
} }
/**
* Initiate download of /version from the auditor.
*
* @param cls auditor where to download /version from
*/
static void
request_version (void *cls)
{
struct TALER_AUDITOR_Handle *auditor = cls;
CURL *eh;
auditor->retry_task = NULL;
GNUNET_assert (NULL == auditor->vr);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Requesting auditor version with URL `%s'.\n",
auditor->vr_url);
eh = TALER_AUDITOR_curl_easy_get_ (auditor->vr_url);
if (NULL == eh)
{
GNUNET_break (0);
auditor->retry_delay = EXCHANGE_LIB_BACKOFF (auditor->retry_delay);
auditor->retry_task = GNUNET_SCHEDULER_add_delayed (auditor->retry_delay,
&request_version,
auditor);
return;
}
GNUNET_break (CURLE_OK ==
curl_easy_setopt (eh,
CURLOPT_TIMEOUT,
(long) 300));
auditor->vr = GNUNET_CURL_job_add (auditor->ctx,
eh,
&version_completed_cb,
auditor);
}
/* ********************* library internal API ********* */ /* ********************* library internal API ********* */
@ -371,8 +370,7 @@ enum GNUNET_GenericReturnValue
TALER_AUDITOR_handle_is_ready_ (struct TALER_AUDITOR_Handle *h) TALER_AUDITOR_handle_is_ready_ (struct TALER_AUDITOR_Handle *h)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Checking if auditor %p (%s) is now ready: %s\n", "Checking if auditor at `%s` is now ready: %s\n",
h,
h->url, h->url,
(MHD_VERSION == h->state) ? "yes" : "no"); (MHD_VERSION == h->state) ? "yes" : "no");
return (MHS_VERSION == h->state) ? GNUNET_YES : GNUNET_NO; return (MHS_VERSION == h->state) ? GNUNET_YES : GNUNET_NO;
@ -401,103 +399,48 @@ TALER_AUDITOR_connect (struct GNUNET_CURL_Context *ctx,
{ {
struct TALER_AUDITOR_Handle *auditor; struct TALER_AUDITOR_Handle *auditor;
/* Disable 100 continue processing */
GNUNET_break (GNUNET_OK ==
GNUNET_CURL_append_header (ctx,
"Expect:"));
auditor = GNUNET_new (struct TALER_AUDITOR_Handle); auditor = GNUNET_new (struct TALER_AUDITOR_Handle);
auditor->version_cb = version_cb;
auditor->version_cb_cls = version_cb_cls;
auditor->retry_delay = GNUNET_TIME_UNIT_SECONDS; /* start slowly */ auditor->retry_delay = GNUNET_TIME_UNIT_SECONDS; /* start slowly */
auditor->ctx = ctx; auditor->ctx = ctx;
auditor->url = GNUNET_strdup (url); auditor->url = GNUNET_strdup (url);
auditor->version_cb = version_cb; auditor->vr_url = TALER_AUDITOR_path_to_url_ (auditor,
auditor->version_cb_cls = version_cb_cls; "/version");
if (NULL == auditor->vr_url)
{
GNUNET_break (0);
GNUNET_free (auditor->url);
GNUNET_free (auditor);
return NULL;
}
auditor->retry_task = GNUNET_SCHEDULER_add_now (&request_version, auditor->retry_task = GNUNET_SCHEDULER_add_now (&request_version,
auditor); auditor);
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Connecting to auditor at URL `%s' (%p).\n", "Connecting to auditor at URL `%s'.\n",
url, url);
auditor);
return auditor; return auditor;
} }
/**
* Initiate download of /version from the auditor.
*
* @param cls auditor where to download /version from
*/
static void
request_version (void *cls)
{
struct TALER_AUDITOR_Handle *auditor = cls;
struct VersionRequest *vr;
CURL *eh;
auditor->retry_task = NULL;
GNUNET_assert (NULL == auditor->vr);
vr = GNUNET_new (struct VersionRequest);
vr->auditor = auditor;
vr->url = TALER_AUDITOR_path_to_url_ (auditor,
"/version");
if (NULL == vr->url)
{
struct TALER_AUDITOR_HttpResponse hr = {
.ec = TALER_EC_GENERIC_CONFIGURATION_INVALID
};
auditor->version_cb (auditor->version_cb_cls,
&hr,
NULL,
TALER_AUDITOR_VC_PROTOCOL_ERROR);
GNUNET_free (vr);
return;
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Requesting auditor version with URL `%s'.\n",
vr->url);
eh = TALER_AUDITOR_curl_easy_get_ (vr->url);
if (NULL == eh)
{
GNUNET_break (0);
auditor->retry_delay = EXCHANGE_LIB_BACKOFF (auditor->retry_delay);
auditor->retry_task = GNUNET_SCHEDULER_add_delayed (auditor->retry_delay,
&request_version,
auditor);
GNUNET_free (vr->url);
GNUNET_free (vr);
return;
}
GNUNET_break (CURLE_OK ==
curl_easy_setopt (eh,
CURLOPT_TIMEOUT,
(long) 300));
vr->job = GNUNET_CURL_job_add (auditor->ctx,
eh,
&version_completed_cb,
vr);
auditor->vr = vr;
}
void void
TALER_AUDITOR_disconnect (struct TALER_AUDITOR_Handle *auditor) TALER_AUDITOR_disconnect (struct TALER_AUDITOR_Handle *auditor)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Disconnecting from auditor at URL `%s' (%p).\n", "Disconnecting from auditor at URL `%s'.\n",
auditor->url, auditor->url);
auditor);
if (NULL != auditor->vr) if (NULL != auditor->vr)
{ {
GNUNET_CURL_job_cancel (auditor->vr->job); GNUNET_CURL_job_cancel (auditor->vr);
free_version_request (auditor->vr);
auditor->vr = NULL; auditor->vr = NULL;
} }
GNUNET_free (auditor->version);
if (NULL != auditor->retry_task) if (NULL != auditor->retry_task)
{ {
GNUNET_SCHEDULER_cancel (auditor->retry_task); GNUNET_SCHEDULER_cancel (auditor->retry_task);
auditor->retry_task = NULL; auditor->retry_task = NULL;
} }
GNUNET_free (auditor->version);
GNUNET_free (auditor->vr_url);
GNUNET_free (auditor->url); GNUNET_free (auditor->url);
GNUNET_free (auditor); GNUNET_free (auditor);
} }