From de3e26303e0069614d4a5aa425e4fa5ddb088b8b Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Fri, 1 Apr 2016 16:15:35 +0200 Subject: implementing #4356, tests still failing, but main logic should now be updated --- src/exchange-lib/exchange_api_wire.c | 319 +++++------------------------------ src/exchange-lib/test_exchange_api.c | 96 +++++------ 2 files changed, 81 insertions(+), 334 deletions(-) (limited to 'src/exchange-lib') diff --git a/src/exchange-lib/exchange_api_wire.c b/src/exchange-lib/exchange_api_wire.c index 27ae1dce7..0e93a9d20 100644 --- a/src/exchange-lib/exchange_api_wire.c +++ b/src/exchange-lib/exchange_api_wire.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014, 2015 GNUnet e.V. + Copyright (C) 2014, 2015, 2016 Inria and GNUnet e.V. 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 @@ -128,257 +128,6 @@ verify_wire_method_signature_ok (const struct TALER_EXCHANGE_WireHandle *wh, } -/** - * Perform the next /wire/method request or signal - * the end of the iteration. - * - * @param wh the wire handle - * @return a handle for this request - */ -static void -request_wire_method (struct TALER_EXCHANGE_WireHandle *wh); - - -/** - * Function called when we're done processing the - * HTTP /wire/METHOD request. - * - * @param cls the `struct TALER_EXCHANGE_WireHandle` - * @param eh the curl request handle - */ -static void -handle_wire_method_finished (void *cls, - CURL *eh) -{ - struct TALER_EXCHANGE_WireHandle *wh = cls; - long response_code; - json_t *json; - - wh->job = NULL; - json = MAC_download_get_result (&wh->db, - eh, - &response_code); - switch (response_code) - { - case 0: - break; - case MHD_HTTP_OK: - { - const char *method; - - method = json_string_value (json_array_get (wh->methods, - wh->methods_off - 1)); - if (GNUNET_OK != - verify_wire_method_signature_ok (wh, - method, - json)) - { - GNUNET_break_op (0); - response_code = 0; - break; - } - break; - } - case MHD_HTTP_FOUND: - /* /wire/test returns a 302 redirect, we should just give - this information back to the callback below */ - break; - case MHD_HTTP_BAD_REQUEST: - /* This should never happen, either us or the exchange is buggy - (or API version conflict); just pass JSON reply to the application */ - break; - case MHD_HTTP_NOT_FOUND: - /* Nothing really to verify, this should never - happen, we should pass the JSON reply to the application */ - break; - case MHD_HTTP_INTERNAL_SERVER_ERROR: - /* Server had an internal issue; we should retry, but this API - leaves this to the application */ - break; - default: - /* unexpected response code */ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u\n", - response_code); - GNUNET_break (0); - response_code = 0; - break; - } - if (0 == response_code) - { - /* signal end of iteration */ - wh->cb (wh->cb_cls, - 0, - NULL, - NULL); - json_decref (json); - TALER_EXCHANGE_wire_cancel (wh); - return; - } - /* pass on successful reply */ - wh->cb (wh->cb_cls, - response_code, - json_string_value (json_array_get (wh->methods, - wh->methods_off-1)), - json); - json_decref (json); - /* trigger request for the next /wire/method */ - request_wire_method (wh); -} - - -/** - * Perform the next /wire/method request or signal - * the end of the iteration. - * - * @param wh the wire handle - * @return a handle for this request - */ -static void -request_wire_method (struct TALER_EXCHANGE_WireHandle *wh) -{ - struct TALER_EXCHANGE_Context *ctx; - CURL *eh; - char *path; - - if (json_array_size (wh->methods) <= wh->methods_off) - { - /* we are done, signal end of iteration */ - wh->cb (wh->cb_cls, - 0, - NULL, - NULL); - TALER_EXCHANGE_wire_cancel (wh); - return; - } - GNUNET_free_non_null (wh->db.buf); - wh->db.buf = NULL; - wh->db.buf_size = 0; - wh->db.eno = 0; - GNUNET_free_non_null (wh->url); - GNUNET_asprintf (&path, - "/wire/%s", - json_string_value (json_array_get (wh->methods, - wh->methods_off++))); - wh->url = MAH_path_to_url (wh->exchange, - path); - GNUNET_free (path); - - eh = curl_easy_init (); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_URL, - wh->url)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_WRITEFUNCTION, - &MAC_download_cb)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_WRITEDATA, - &wh->db)); - /* The default is 'disabled', but let's be sure */ - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_FOLLOWLOCATION, - (long) 0)); - ctx = MAH_handle_to_context (wh->exchange); - wh->job = MAC_job_add (ctx, - eh, - GNUNET_YES, - &handle_wire_method_finished, - wh); - TALER_EXCHANGE_perform (ctx); -} - - -/** - * Verify that the signature on the "200 OK" response - * for /wire from the exchange is valid. - * - * @param wh wire handle - * @param json json reply with the signature - * @return NULL if @a json is invalid, otherwise the - * "methods" array (with an RC of 1) - */ -static json_t * -verify_wire_signature_ok (const struct TALER_EXCHANGE_WireHandle *wh, - json_t *json) -{ - struct TALER_ExchangeSignatureP exchange_sig; - struct TALER_ExchangePublicKeyP exchange_pub; - struct TALER_ExchangeWireSupportMethodsPS mp; - json_t *methods; - const struct TALER_EXCHANGE_Keys *key_state; - struct GNUNET_HashContext *hc; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_fixed_auto ("sig", &exchange_sig), - GNUNET_JSON_spec_fixed_auto ("pub", &exchange_pub), - GNUNET_JSON_spec_json ("methods", &methods), - GNUNET_JSON_spec_end() - }; - unsigned int i; - - if (GNUNET_OK != - GNUNET_JSON_parse (json, - spec, - NULL, NULL)) - { - GNUNET_break_op (0); - return NULL; - } - if (! json_is_array (methods)) - { - GNUNET_break_op (0); - GNUNET_JSON_parse_free (spec); - return NULL; - } - - key_state = TALER_EXCHANGE_get_keys (wh->exchange); - if (GNUNET_OK != - TALER_EXCHANGE_test_signing_key (key_state, - &exchange_pub)) - { - GNUNET_break_op (0); - return NULL; - } - hc = GNUNET_CRYPTO_hash_context_start (); - for (i=0;imethods = methods; - request_wire_method (wh); - return; + else + { + /* some supported methods were invalid, release 'keep', preserve + full 'json' for application-level error handling. */ + json_decref (keep); + } } break; case MHD_HTTP_BAD_REQUEST: @@ -440,19 +217,9 @@ handle_wire_finished (void *cls, response_code = 0; break; } - if (0 != response_code) - { - /* pass on successful reply */ - wh->cb (wh->cb_cls, - response_code, - NULL, - json); - } - /* signal end of iteration */ wh->cb (wh->cb_cls, - 0, - NULL, - NULL); + response_code, + json); if (NULL != json) json_decref (json); TALER_EXCHANGE_wire_cancel (wh); @@ -481,8 +248,8 @@ handle_wire_finished (void *cls, */ struct TALER_EXCHANGE_WireHandle * TALER_EXCHANGE_wire (struct TALER_EXCHANGE_Handle *exchange, - TALER_EXCHANGE_WireResultCallback wire_cb, - void *wire_cb_cls) + TALER_EXCHANGE_WireResultCallback wire_cb, + void *wire_cb_cls) { struct TALER_EXCHANGE_WireHandle *wh; struct TALER_EXCHANGE_Context *ctx; diff --git a/src/exchange-lib/test_exchange_api.c b/src/exchange-lib/test_exchange_api.c index 2a7f670cd..6eae08f4d 100644 --- a/src/exchange-lib/test_exchange_api.c +++ b/src/exchange-lib/test_exchange_api.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014, 2015, 2016 GNUnet e.V. + Copyright (C) 2014, 2015, 2016 GNUnet e.V. and Inria 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 @@ -1213,76 +1213,56 @@ find_pk (const struct TALER_EXCHANGE_Keys *keys, * Callbacks called with the result(s) of a * wire format inquiry request to the exchange. * - * The callback is invoked multiple times, once for each supported @a - * method. Finally, it is invoked one more time with cls/0/NULL/NULL - * to indicate the end of the iteration. If any request fails to - * generate a valid response from the exchange, @a http_status will also - * be zero and the iteration will also end. Thus, the iteration - * always ends with a final call with an @a http_status of 0. If the - * @a http_status is already 0 on the first call, then the response to - * the /wire request was invalid. Later, clients can tell the - * difference between @a http_status of 0 indicating a failed - * /wire/method request and a regular end of the iteration by @a - * method being non-NULL. If the exchange simply correctly asserts that - * it does not support any methods, @a method will be NULL but the @a - * http_status will be #MHD_HTTP_OK for the first call (followed by a - * cls/0/NULL/NULL call to signal the end of the iteration). - * * @param cls closure with the interpreter state * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful request; * 0 if the exchange's reply is bogus (fails to follow the protocol) - * @param method wire format method supported, i.e. "test" or "sepa", or NULL - * if already the /wire request failed. * @param obj the received JSON reply, if successful this should be the wire - * format details as provided by /wire/METHOD/, or NULL if the - * reply was not in JSON format (in this case, the client might - * want to do an HTTP request to /wire/METHOD/ with a browser to - * provide more information to the user about the @a method). + * format details as provided by /wire. */ static void wire_cb (void *cls, unsigned int http_status, - const char *method, json_t *obj) { struct InterpreterState *is = cls; struct Command *cmd = &is->commands[is->ip]; - if (0 == http_status) - { - /* 0 always signals the end of the iteration */ - cmd->details.wire.wh = NULL; - } - else if ( (NULL != method) && - (0 != strcasecmp (method, - cmd->details.wire.format)) ) - { - /* not the method we care about, skip */ - return; - } if (cmd->expected_response_code != http_status) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u to command %s/%s\n", + "Unexpected response code %u to command %s\n", http_status, - cmd->label, - method); + cmd->label); json_dumpf (obj, stderr, 0); fail (is); return; } - if (0 == http_status) + switch (http_status) { - /* end of iteration, move to next command */ - is->ip++; - is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, - is); - return; + case MHD_HTTP_OK: + { + json_t *method; + + method = json_object_get (obj, + cmd->details.wire.format); + if (NULL == method) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Expected method `%s' not included in response to command %s\n", + cmd->details.wire.format, + cmd->label); + json_dumpf (obj, stderr, 0); + fail (is); + return; + } + } + break; + default: + break; } - /* For now, we only support to be called only once - with a "positive" result; so we switch to an - expected value of 0 for the 2nd iteration */ - cmd->expected_response_code = 0; + is->ip++; + is->task = GNUNET_SCHEDULER_add_now (&interpreter_run, + is); } @@ -1899,9 +1879,9 @@ interpreter_run (void *cls, /* finally, use private key from withdraw sign command */ cmd->details.refresh_link.rlh = TALER_EXCHANGE_refresh_link (exchange, - &ref->details.reserve_withdraw.coin_priv, - &link_cb, - is); + &ref->details.reserve_withdraw.coin_priv, + &link_cb, + is); if (NULL == cmd->details.refresh_link.rlh) { GNUNET_break (0); @@ -1912,8 +1892,8 @@ interpreter_run (void *cls, return; case OC_WIRE: cmd->details.wire.wh = TALER_EXCHANGE_wire (exchange, - &wire_cb, - is); + &wire_cb, + is); trigger_context_task (); return; case OC_WIRE_DEPOSITS: @@ -1926,9 +1906,9 @@ interpreter_run (void *cls, } cmd->details.wire_deposits.wdh = TALER_EXCHANGE_wire_deposits (exchange, - &cmd->details.wire_deposits.wtid, - &wire_deposits_cb, - is); + &cmd->details.wire_deposits.wtid, + &wire_deposits_cb, + is); trigger_context_task (); return; case OC_DEPOSIT_WTID: @@ -2337,14 +2317,14 @@ run (void *cls, #if WIRE_TEST { .oc = OC_WIRE, .label = "wire-test", - /* /wire/test replies with a 200 OK */ + /* expecting 'test' method in response */ .expected_response_code = MHD_HTTP_OK, .details.wire.format = "test" }, #endif #if WIRE_SEPA { .oc = OC_WIRE, .label = "wire-sepa", - /* /wire/sepa replies with a 200 redirect */ + /* expecting 'sepa' method in response */ .expected_response_code = MHD_HTTP_OK, .details.wire.format = "sepa" }, #endif -- cgit v1.2.3