From 17789253e9194c66bb9ddb081425a35212ac7bf3 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 21 Jun 2023 07:53:17 +0200 Subject: [PATCH] ensure forward-compatibility for auditor C API --- src/include/taler_auditor_service.h | 111 +++++++++++++++--- src/lib/auditor_api_deposit_confirmation.c | 40 +++---- src/lib/auditor_api_exchanges.c | 50 ++++---- src/lib/auditor_api_handle.c | 49 +++----- src/lib/exchange_api_handle.c | 25 ++-- src/lib/exchange_api_handle.h | 7 +- src/testing/test_auditor_api_version.c | 13 +- ...ing_api_cmd_auditor_deposit_confirmation.c | 10 +- .../testing_api_cmd_auditor_exchanges.c | 21 ++-- src/testing/testing_api_cmd_get_auditor.c | 12 +- 10 files changed, 200 insertions(+), 138 deletions(-) diff --git a/src/include/taler_auditor_service.h b/src/include/taler_auditor_service.h index 0beff983d..9d721550b 100644 --- a/src/include/taler_auditor_service.h +++ b/src/include/taler_auditor_service.h @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2021 Taler Systems SA + Copyright (C) 2014-2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software @@ -146,21 +146,54 @@ struct TALER_AUDITOR_HttpResponse }; +/** + * Response to /version request. + */ +struct TALER_AUDITOR_VersionResponse +{ + /** + * HTTP response. + */ + struct TALER_AUDITOR_HttpResponse hr; + + /** + * Details depending on HTTP status. + */ + union + { + + /** + * Details for #MHD_HTTP_OK. + */ + struct + { + + /** + * Protocol compatibility evaluation. + */ + enum TALER_AUDITOR_VersionCompatibility compat; + + /** + * Version data returned by /config. + */ + struct TALER_AUDITOR_VersionInformation vi; + + } ok; + } details; + +}; + + /** * Function called with information about the auditor. * * @param cls closure - * @param hr HTTP response data - * @param vi basic information about the auditor - * @param compat protocol compatibility information + * @param vr response data */ -// FIXME: bad API! typedef void (*TALER_AUDITOR_VersionCallback) ( void *cls, - const struct TALER_AUDITOR_HttpResponse *hr, - const struct TALER_AUDITOR_VersionInformation *vi, - enum TALER_AUDITOR_VersionCompatibility compat); + const struct TALER_AUDITOR_VersionResponse *vr); /** @@ -206,17 +239,29 @@ TALER_AUDITOR_disconnect (struct TALER_AUDITOR_Handle *auditor); struct TALER_AUDITOR_DepositConfirmationHandle; +/** + * Response to /deposit-confirmation request. + */ +struct TALER_AUDITOR_DepositConfirmationResponse +{ + /** + * HTTP response. + */ + struct TALER_AUDITOR_HttpResponse hr; +}; + + /** * Signature of functions called with the result from our call to the * auditor's /deposit-confirmation handler. * * @param cls closure - * @param hr HTTP response data + * @param dcr response data */ typedef void (*TALER_AUDITOR_DepositConfirmationResultCallback)( void *cls, - const struct TALER_AUDITOR_HttpResponse *hr); + const struct TALER_AUDITOR_DepositConfirmationResponse *dcr); /** @@ -313,20 +358,54 @@ struct TALER_AUDITOR_ExchangeInfo }; +/** + * Response to GET /exchanges request. + */ +struct TALER_AUDITOR_ListExchangesResponse +{ + /** + * HTTP response. + */ + struct TALER_AUDITOR_HttpResponse hr; + + /** + * Details depending on HTTP status. + */ + union + { + + /** + * Details for #MHD_HTTP_OK. + */ + struct + { + + /** + * Length of the @e ei array. + */ + unsigned int num_exchanges; + + /** + * Array with information about exchanges + * audited by this auditor. + */ + const struct TALER_AUDITOR_ExchangeInfo *ei; + } ok; + } details; +}; + + /** * Function called with the result from /exchanges. * * @param cls closure - * @param hr HTTP response data - * @param num_exchanges length of array at @a ei - * @param ei information about exchanges returned by the auditor + * @param ler response data */ typedef void (*TALER_AUDITOR_ListExchangesResultCallback)( void *cls, - const struct TALER_AUDITOR_HttpResponse *hr, - unsigned int num_exchanges, - const struct TALER_AUDITOR_ExchangeInfo *ei); + const struct TALER_AUDITOR_ListExchangesResponse *ler); + /** * Submit an /exchanges request to the auditor and get the diff --git a/src/lib/auditor_api_deposit_confirmation.c b/src/lib/auditor_api_deposit_confirmation.c index 55a05d962..93cdaed93 100644 --- a/src/lib/auditor_api_deposit_confirmation.c +++ b/src/lib/auditor_api_deposit_confirmation.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2021 Taler Systems SA + Copyright (C) 2014-2023 Taler Systems SA 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 @@ -87,64 +87,64 @@ handle_deposit_confirmation_finished (void *cls, { const json_t *json = djson; struct TALER_AUDITOR_DepositConfirmationHandle *dh = cls; - struct TALER_AUDITOR_HttpResponse hr = { - .reply = json, - .http_status = (unsigned int) response_code + struct TALER_AUDITOR_DepositConfirmationResponse dcr = { + .hr.reply = json, + .hr.http_status = (unsigned int) response_code }; dh->job = NULL; switch (response_code) { case 0: - hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + dcr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; break; case MHD_HTTP_OK: - hr.ec = TALER_EC_NONE; + dcr.hr.ec = TALER_EC_NONE; break; case MHD_HTTP_BAD_REQUEST: - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + dcr.hr.ec = TALER_JSON_get_error_code (json); + dcr.hr.hint = TALER_JSON_get_error_hint (json); /* This should never happen, either us or the auditor is buggy (or API version conflict); just pass JSON reply to the application */ break; case MHD_HTTP_FORBIDDEN: - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + dcr.hr.ec = TALER_JSON_get_error_code (json); + dcr.hr.hint = TALER_JSON_get_error_hint (json); /* Nothing really to verify, auditor says one of the signatures is invalid; as we checked them, this should never happen, we should pass the JSON reply to the application */ break; case MHD_HTTP_NOT_FOUND: - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + dcr.hr.ec = TALER_JSON_get_error_code (json); + dcr.hr.hint = TALER_JSON_get_error_hint (json); /* Nothing really to verify, this should never happen, we should pass the JSON reply to the application */ break; case MHD_HTTP_GONE: - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + dcr.hr.ec = TALER_JSON_get_error_code (json); + dcr.hr.hint = TALER_JSON_get_error_hint (json); /* Nothing really to verify, auditor says one of the signatures is invalid; as we checked them, this should never happen, we should pass the JSON reply to the application */ break; case MHD_HTTP_INTERNAL_SERVER_ERROR: - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + dcr.hr.ec = TALER_JSON_get_error_code (json); + dcr.hr.hint = TALER_JSON_get_error_hint (json); /* Server had an internal issue; we should retry, but this API leaves this to the application */ break; default: /* unexpected response code */ - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + dcr.hr.ec = TALER_JSON_get_error_code (json); + dcr.hr.hint = TALER_JSON_get_error_hint (json); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected response code %u/%d for auditor deposit confirmation\n", (unsigned int) response_code, - hr.ec); + dcr.hr.ec); break; } dh->cb (dh->cb_cls, - &hr); + &dcr); TALER_AUDITOR_deposit_confirmation_cancel (dh); } diff --git a/src/lib/auditor_api_exchanges.c b/src/lib/auditor_api_exchanges.c index 7327f11b2..9f35c7077 100644 --- a/src/lib/auditor_api_exchanges.c +++ b/src/lib/auditor_api_exchanges.c @@ -89,16 +89,16 @@ handle_exchanges_finished (void *cls, const json_t *ja; unsigned int ja_len; struct TALER_AUDITOR_ListExchangesHandle *leh = cls; - struct TALER_AUDITOR_HttpResponse hr = { - .reply = json, - .http_status = (unsigned int) response_code + struct TALER_AUDITOR_ListExchangesResponse ler = { + .hr.reply = json, + .hr.http_status = (unsigned int) response_code }; leh->job = NULL; switch (response_code) { case 0: - hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + ler.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; break; case MHD_HTTP_OK: ja = json_object_get (json, @@ -107,8 +107,8 @@ handle_exchanges_finished (void *cls, (! json_is_array (ja)) ) { GNUNET_break (0); - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - hr.http_status = 0; + ler.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + ler.hr.http_status = 0; break; } @@ -116,12 +116,12 @@ handle_exchanges_finished (void *cls, if (ja_len > MAX_EXCHANGES) { GNUNET_break (0); - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - hr.http_status = 0; + ler.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + ler.hr.http_status = 0; break; } { - struct TALER_AUDITOR_ExchangeInfo ei[ja_len]; + struct TALER_AUDITOR_ExchangeInfo ei[GNUNET_NZL (ja_len)]; bool ok; ok = true; @@ -141,54 +141,52 @@ handle_exchanges_finished (void *cls, { GNUNET_break_op (0); ok = false; - hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - hr.http_status = 0; + ler.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + ler.hr.http_status = 0; break; } } if (! ok) break; + ler.details.ok.ei = ei; + ler.details.ok.num_exchanges = ja_len; leh->cb (leh->cb_cls, - &hr, - ja_len, - ei); + &ler); TALER_AUDITOR_list_exchanges_cancel (leh); return; } case MHD_HTTP_BAD_REQUEST: /* This should never happen, either us or the auditor is buggy (or API version conflict); just pass JSON reply to the application */ - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + ler.hr.ec = TALER_JSON_get_error_code (json); + ler.hr.hint = TALER_JSON_get_error_hint (json); break; case MHD_HTTP_NOT_FOUND: /* Nothing really to verify, this should never happen, we should pass the JSON reply to the application */ - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + ler.hr.ec = TALER_JSON_get_error_code (json); + ler.hr.hint = TALER_JSON_get_error_hint (json); break; case MHD_HTTP_INTERNAL_SERVER_ERROR: /* Server had an internal issue; we should retry, but this API leaves this to the application */ - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + ler.hr.ec = TALER_JSON_get_error_code (json); + ler.hr.hint = TALER_JSON_get_error_hint (json); break; default: /* unexpected response code */ - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + ler.hr.ec = TALER_JSON_get_error_code (json); + ler.hr.hint = TALER_JSON_get_error_hint (json); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected response code %u/%d for auditor list-exchanges request\n", (unsigned int) response_code, - (int) hr.ec); + (int) ler.hr.ec); GNUNET_break_op (0); break; } if (NULL != leh->cb) leh->cb (leh->cb_cls, - &hr, - 0, - NULL); + &ler); TALER_AUDITOR_list_exchanges_cancel (leh); } diff --git a/src/lib/auditor_api_handle.c b/src/lib/auditor_api_handle.c index 14869de43..318b63f94 100644 --- a/src/lib/auditor_api_handle.c +++ b/src/lib/auditor_api_handle.c @@ -239,10 +239,9 @@ version_completed_cb (void *cls, { struct TALER_AUDITOR_Handle *auditor = cls; const json_t *resp_obj = gresp_obj; - enum TALER_AUDITOR_VersionCompatibility vc; - struct TALER_AUDITOR_HttpResponse hr = { - .reply = resp_obj, - .http_status = (unsigned int) response_code + struct TALER_AUDITOR_VersionResponse vr = { + .hr.reply = resp_obj, + .hr.http_status = (unsigned int) response_code }; auditor->vr = NULL; @@ -250,7 +249,6 @@ version_completed_cb (void *cls, "Received version from URL `%s' with status %ld.\n", auditor->url, response_code); - vc = TALER_AUDITOR_VC_PROTOCOL_ERROR; switch (response_code) { case 0: @@ -268,28 +266,33 @@ version_completed_cb (void *cls, { GNUNET_break_op (0); TALER_LOG_WARNING ("NULL body for a 200-OK /config\n"); - hr.http_status = 0; - hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + vr.hr.http_status = 0; + vr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; break; } - hr.ec = decode_version_json (resp_obj, - auditor, - &vc); - if (TALER_EC_NONE != hr.ec) + vr.hr.ec = decode_version_json (resp_obj, + auditor, + &vr.details.ok.compat); + if (TALER_EC_NONE != vr.hr.ec) { GNUNET_break_op (0); - hr.http_status = 0; + vr.hr.http_status = 0; break; } + auditor->state = MHS_VERSION; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Auditor %s is ready!\n", + auditor->url); + vr.details.ok.vi = auditor->vi; auditor->retry_delay = GNUNET_TIME_UNIT_ZERO; /* restart quickly */ break; default: - hr.ec = TALER_JSON_get_error_code (resp_obj); - hr.hint = TALER_JSON_get_error_hint (resp_obj); + vr.hr.ec = TALER_JSON_get_error_code (resp_obj); + vr.hr.hint = TALER_JSON_get_error_hint (resp_obj); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected response code %u/%d\n", (unsigned int) response_code, - (int) hr.ec); + (int) vr.hr.ec); break; } if (MHD_HTTP_OK != response_code) @@ -299,23 +302,9 @@ version_completed_cb (void *cls, auditor->url, (unsigned int) response_code); auditor->state = MHS_FAILED; - /* notify application that we failed */ - auditor->version_cb (auditor->version_cb_cls, - &hr, - NULL, - vc); - return; } - TALER_LOG_DEBUG ("Switching auditor state to 'version'\n"); - auditor->state = MHS_VERSION; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Auditor %s is ready!\n", - auditor->url); - /* notify application about the key information */ auditor->version_cb (auditor->version_cb_cls, - &hr, - &auditor->vi, - vc); + &vr); } diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c index 20bac43a0..7b815f28b 100644 --- a/src/lib/exchange_api_handle.c +++ b/src/lib/exchange_api_handle.c @@ -168,19 +168,20 @@ struct KeysRequest void -TEAH_acc_confirmation_cb (void *cls, - const struct TALER_AUDITOR_HttpResponse *hr) +TEAH_acc_confirmation_cb ( + void *cls, + const struct TALER_AUDITOR_DepositConfirmationResponse *dcr) { struct TEAH_AuditorInteractionEntry *aie = cls; struct TEAH_AuditorListEntry *ale = aie->ale; - if (MHD_HTTP_OK != hr->http_status) + if (MHD_HTTP_OK != dcr->hr.http_status) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Failed to submit deposit confirmation to auditor `%s' with HTTP status %d (EC: %d). This is acceptable if it does not happen often.\n", ale->auditor_url, - hr->http_status, - hr->ec); + dcr->hr.http_status, + dcr->hr.ec); } GNUNET_CONTAINER_DLL_remove (ale->ai_head, ale->ai_tail, @@ -579,21 +580,17 @@ parse_global_fee (struct TALER_EXCHANGE_GlobalFee *gf, * auditor as 'up'. * * @param cls closure, a `struct TEAH_AuditorListEntry *` - * @param hr http response from the auditor - * @param vi basic information about the auditor - * @param compat protocol compatibility information + * @param vr response from the auditor */ static void auditor_version_cb ( void *cls, - const struct TALER_AUDITOR_HttpResponse *hr, - const struct TALER_AUDITOR_VersionInformation *vi, - enum TALER_AUDITOR_VersionCompatibility compat) + const struct TALER_AUDITOR_VersionResponse *vr) { struct TEAH_AuditorListEntry *ale = cls; + enum TALER_AUDITOR_VersionCompatibility compat; - (void) hr; - if (NULL == vi) + if (MHD_HTTP_OK != vr->hr.http_status) { /* In this case, we don't mark the auditor as 'up' */ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, @@ -601,7 +598,7 @@ auditor_version_cb ( ale->auditor_url); return; } - + compat = vr->details.ok.compat; if (0 != (TALER_AUDITOR_VC_INCOMPATIBLE & compat)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, diff --git a/src/lib/exchange_api_handle.h b/src/lib/exchange_api_handle.h index 3b1d875fb..47be99d4e 100644 --- a/src/lib/exchange_api_handle.h +++ b/src/lib/exchange_api_handle.h @@ -193,11 +193,12 @@ typedef struct TEAH_AuditorInteractionEntry * * auditor's /deposit-confirmation handler. * * @param cls closure of type `struct TEAH_AuditorInteractionEntry *` - * @param hr HTTP response + * @param dcr response */ void -TEAH_acc_confirmation_cb (void *cls, - const struct TALER_AUDITOR_HttpResponse *hr); +TEAH_acc_confirmation_cb ( + void *cls, + const struct TALER_AUDITOR_DepositConfirmationResponse *dcr); /** diff --git a/src/testing/test_auditor_api_version.c b/src/testing/test_auditor_api_version.c index 252369fa7..1b4f2b17d 100644 --- a/src/testing/test_auditor_api_version.c +++ b/src/testing/test_auditor_api_version.c @@ -82,20 +82,15 @@ do_timeout (void *cls) * Function called with information about the auditor. * * @param cls closure - * @param hr http response details - * @param vi basic information about the auditor - * @param compat protocol compatibility information + * @param vr response details */ static void version_cb (void *cls, - const struct TALER_AUDITOR_HttpResponse *hr, - const struct TALER_AUDITOR_VersionInformation *vi, - enum TALER_AUDITOR_VersionCompatibility compat) + const struct TALER_AUDITOR_VersionResponse *vr) { (void) cls; - (void) hr; - if ( (NULL != vi) && - (TALER_AUDITOR_VC_MATCH == compat) ) + if ( (MHD_HTTP_OK == vr->hr.http_status) && + (TALER_AUDITOR_VC_MATCH == vr->details.ok.compat) ) global_ret = 0; else global_ret = 2; diff --git a/src/testing/testing_api_cmd_auditor_deposit_confirmation.c b/src/testing/testing_api_cmd_auditor_deposit_confirmation.c index c6a1516e7..c2a4bcc24 100644 --- a/src/testing/testing_api_cmd_auditor_deposit_confirmation.c +++ b/src/testing/testing_api_cmd_auditor_deposit_confirmation.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2018, 2021 Taler Systems SA + Copyright (C) 2018-2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -132,13 +132,15 @@ do_retry (void *cls) * to check if the response code is acceptable. * * @param cls closure. - * @param hr HTTP response details + * @param dcr response details */ static void -deposit_confirmation_cb (void *cls, - const struct TALER_AUDITOR_HttpResponse *hr) +deposit_confirmation_cb ( + void *cls, + const struct TALER_AUDITOR_DepositConfirmationResponse *dcr) { struct DepositConfirmationState *dcs = cls; + const struct TALER_AUDITOR_HttpResponse *hr = &dcr->hr; dcs->dc = NULL; if (dcs->expected_response_code != hr->http_status) diff --git a/src/testing/testing_api_cmd_auditor_exchanges.c b/src/testing/testing_api_cmd_auditor_exchanges.c index 184c2bb2e..ea9ace3e4 100644 --- a/src/testing/testing_api_cmd_auditor_exchanges.c +++ b/src/testing/testing_api_cmd_auditor_exchanges.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2018 Taler Systems SA + Copyright (C) 2018-2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -127,11 +127,10 @@ do_retry (void *cls) */ static void exchanges_cb (void *cls, - const struct TALER_AUDITOR_HttpResponse *hr, - unsigned int num_exchanges, - const struct TALER_AUDITOR_ExchangeInfo *ei) + const struct TALER_AUDITOR_ListExchangesResponse *ler) { struct ExchangesState *es = cls; + const struct TALER_AUDITOR_HttpResponse *hr = &ler->hr; es->leh = NULL; if (es->expected_response_code != hr->http_status) @@ -164,24 +163,30 @@ exchanges_cb (void *cls, hr->http_status); return; } + if (MHD_HTTP_OK != hr->http_status) + { + TALER_TESTING_interpreter_next (es->is); + return; + } if (NULL != es->exchange_url) { - unsigned int found = GNUNET_NO; + bool found = false; + unsigned int num_exchanges = ler->details.ok.num_exchanges; + const struct TALER_AUDITOR_ExchangeInfo *ei = ler->details.ok.ei; for (unsigned int i = 0; iexchange_url, ei[i].exchange_url)) - found = GNUNET_YES; - if (GNUNET_NO == found) + found = true; + if (! found) { TALER_LOG_ERROR ("Exchange '%s' doesn't exist at this auditor\n", es->exchange_url); TALER_TESTING_interpreter_fail (es->is); return; } - TALER_LOG_DEBUG ("Exchange '%s' exists at this auditor!\n", es->exchange_url); } diff --git a/src/testing/testing_api_cmd_get_auditor.c b/src/testing/testing_api_cmd_get_auditor.c index 42c887da9..2e9961c36 100644 --- a/src/testing/testing_api_cmd_get_auditor.c +++ b/src/testing/testing_api_cmd_get_auditor.c @@ -70,23 +70,19 @@ struct GetAuditorState * Function called with information about the auditor. * * @param cls closure - * @param hr HTTP response data - * @param vi basic information about the auditor - * @param compat protocol compatibility information + * @param vr response data */ static void version_cb ( void *cls, - const struct TALER_AUDITOR_HttpResponse *hr, - const struct TALER_AUDITOR_VersionInformation *vi, - enum TALER_AUDITOR_VersionCompatibility compat) + const struct TALER_AUDITOR_VersionResponse *vr) { struct GetAuditorState *gas = cls; - if (MHD_HTTP_OK != hr->http_status) + if (MHD_HTTP_OK != vr->hr.http_status) { TALER_TESTING_unexpected_status (gas->is, - hr->http_status); + vr->hr.http_status); return; } TALER_TESTING_interpreter_next (gas->is);