diff --git a/src/mint-lib/mint_api_admin.c b/src/mint-lib/mint_api_admin.c index 47158665a..472b02e7d 100644 --- a/src/mint-lib/mint_api_admin.c +++ b/src/mint-lib/mint_api_admin.c @@ -31,15 +31,6 @@ #include "taler_signatures.h" -/** - * Print JSON parsing related error information - */ -#define JSON_WARN(error) \ - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, \ - "JSON parsing failed at %s:%u: %s (%s)", \ - __FILE__, __LINE__, error.text, error.source) - - /** * @brief An admin/add/incoming Handle */ @@ -84,18 +75,7 @@ struct TALER_MINT_AdminAddIncomingHandle /** * Download buffer */ - void *buf; - - /** - * The size of the download buffer - */ - size_t buf_size; - - /** - * Error code (based on libc errno) if we failed to download - * (i.e. response too large). - */ - int eno; + struct MAC_DownloadBuffer db; }; @@ -113,35 +93,12 @@ handle_admin_add_incoming_finished (void *cls, { struct TALER_MINT_AdminAddIncomingHandle *aai = cls; long response_code; - json_error_t error; json_t *json; aai->job = NULL; - json = NULL; - if (0 == aai->eno) - { - json = json_loadb (aai->buf, - aai->buf_size, - JSON_REJECT_DUPLICATES | JSON_DISABLE_EOF_CHECK, - &error); - if (NULL == json) - { - JSON_WARN (error); - response_code = 0; - } - } - if (NULL != json) - { - if (CURLE_OK != - curl_easy_getinfo (eh, - CURLINFO_RESPONSE_CODE, - &response_code)) - { - /* unexpected error... */ - GNUNET_break (0); - response_code = 0; - } - } + json = MAC_download_get_result (&aai->db, + eh, + &response_code); switch (response_code) { case 0: @@ -170,6 +127,9 @@ handle_admin_add_incoming_finished (void *cls, 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; @@ -182,49 +142,6 @@ handle_admin_add_incoming_finished (void *cls, } -/** - * Callback used when downloading the reply to a /admin/add/incoming - * request. Just appends all of the data to the `buf` in the `struct - * TALER_MINT_AdminAddIncomingHandle` for further processing. The size - * of the download is limited to #GNUNET_MAX_MALLOC_CHECKED, if the - * download exceeds this size, we abort with an error. - * - * @param bufptr data downloaded via HTTP - * @param size size of an item in @a bufptr - * @param nitems number of items in @a bufptr - * @param cls the `struct TALER_MINT_DepositHandle` - * @return number of bytes processed from @a bufptr - */ -static int -admin_add_incoming_download_cb (char *bufptr, - size_t size, - size_t nitems, - void *cls) -{ - struct TALER_MINT_AdminAddIncomingHandle *aai = cls; - size_t msize; - void *buf; - - if (0 == size * nitems) - { - /* Nothing (left) to do */ - return 0; - } - msize = size * nitems; - if ( (msize + aai->buf_size) >= GNUNET_MAX_MALLOC_CHECKED) - { - aai->eno = ENOMEM; - return 0; /* signals an error to curl */ - } - aai->buf = GNUNET_realloc (aai->buf, - aai->buf_size + msize); - buf = aai->buf + aai->buf_size; - memcpy (buf, bufptr, msize); - aai->buf_size += msize; - return msize; -} - - /** * Notify the mint that we have received an incoming transaction * which fills a reserve. Note that this API is an administrative @@ -265,7 +182,7 @@ TALER_MINT_admin_add_incoming (struct TALER_MINT_Handle *mint, return NULL; } admin_obj = json_pack ("{s:o, s:o," /* reserve_pub/amount */ - " s:o, s:o}", /* execution_Date/wire */ + " s:o, s:O}", /* execution_Date/wire */ "reserve_pub", TALER_json_from_data (reserve_pub, sizeof (*reserve_pub)), "amount", TALER_json_from_amount (amount), @@ -297,21 +214,15 @@ TALER_MINT_admin_add_incoming (struct TALER_MINT_Handle *mint, GNUNET_assert (CURLE_OK == curl_easy_setopt (eh, CURLOPT_WRITEFUNCTION, - &admin_add_incoming_download_cb)); + &MAC_download_cb)); GNUNET_assert (CURLE_OK == curl_easy_setopt (eh, CURLOPT_WRITEDATA, - aai)); - GNUNET_assert (NULL != (aai->headers = - curl_slist_append (aai->headers, - "Content-Type: application/json"))); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_HTTPHEADER, - aai->headers)); + &aai->db)); ctx = MAH_handle_to_context (mint); aai->job = MAC_job_add (ctx, eh, + GNUNET_YES, &handle_admin_add_incoming_finished, aai); return aai; @@ -333,6 +244,7 @@ TALER_MINT_admin_add_incoming_cancel (struct TALER_MINT_AdminAddIncomingHandle * aai->job = NULL; } curl_slist_free_all (aai->headers); + GNUNET_free_non_null (aai->db.buf); GNUNET_free (aai->url); GNUNET_free (aai->json_enc); GNUNET_free (aai); diff --git a/src/mint-lib/mint_api_context.c b/src/mint-lib/mint_api_context.c index 2daba89e7..9beeef149 100644 --- a/src/mint-lib/mint_api_context.c +++ b/src/mint-lib/mint_api_context.c @@ -34,9 +34,18 @@ * @param code what was the curl error code */ #define CURL_STRERROR(type, function, code) \ - GNUNET_log (type, "Curl function `%s' has failed at `%s:%d' with error: %s", \ + GNUNET_log (type, \ + "Curl function `%s' has failed at `%s:%d' with error: %s\n", \ function, __FILE__, __LINE__, curl_easy_strerror (code)); +/** + * Print JSON parsing related error information + */ +#define JSON_WARN(error) \ + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, \ + "JSON parsing failed at %s:%u: %s (%s)\n", \ + __FILE__, __LINE__, error.text, error.source) + /** * Failsafe flag. Raised if our constructor fails to initialize @@ -109,6 +118,12 @@ struct TALER_MINT_Context */ struct MAC_Job *jobs_tail; + /** + * HTTP header "application/json", created once and used + * for all requests that need it. + */ + struct curl_slist *json_header; + }; @@ -146,6 +161,9 @@ TALER_MINT_init () ctx = GNUNET_new (struct TALER_MINT_Context); ctx->multi = multi; ctx->share = share; + GNUNET_assert (NULL != (ctx->json_header = + curl_slist_append (NULL, + "Content-Type: application/json"))); return ctx; } @@ -157,20 +175,31 @@ TALER_MINT_init () * instead use #MAC_easy_to_closure to extract the @a jcc_cls argument * from a valid @a eh afterwards. * + * This function modifies the CURL handle to add the + * "Content-Type: application/json" header if @a add_json is set. + * * @param ctx context to execute the job in * @param eh curl easy handle for the request, will * be executed AND cleaned up + * @param add_json add "application/json" content type header * @param jcc callback to invoke upon completion * @param jcc_cls closure for @a jcc */ struct MAC_Job * MAC_job_add (struct TALER_MINT_Context *ctx, CURL *eh, + int add_json, MAC_JobCompletionCallback jcc, void *jcc_cls) { struct MAC_Job *job; + if (GNUNET_YES == add_json) + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_HTTPHEADER, + ctx->json_header)); + job = GNUNET_new (struct MAC_Job); job->easy_handle = eh; job->ctx = ctx; @@ -333,10 +362,112 @@ TALER_MINT_fini (struct TALER_MINT_Context *ctx) GNUNET_assert (NULL == ctx->jobs_head); curl_share_cleanup (ctx->share); curl_multi_cleanup (ctx->multi); + curl_slist_free_all (ctx->json_header); GNUNET_free (ctx); } +/** + * Callback used when downloading the reply to an HTTP request. + * Just appends all of the data to the `buf` in the + * `struct MAC_DownloadBuffer` for further processing. The size of + * the download is limited to #GNUNET_MAX_MALLOC_CHECKED, if + * the download exceeds this size, we abort with an error. + * + * @param bufptr data downloaded via HTTP + * @param size size of an item in @a bufptr + * @param nitems number of items in @a bufptr + * @param cls the `struct KeysRequest` + * @return number of bytes processed from @a bufptr + */ +size_t +MAC_download_cb (char *bufptr, + size_t size, + size_t nitems, + void *cls) +{ + struct MAC_DownloadBuffer *db = cls; + size_t msize; + void *buf; + + if (0 == size * nitems) + { + /* Nothing (left) to do */ + return 0; + } + msize = size * nitems; + if ( (msize + db->buf_size) >= GNUNET_MAX_MALLOC_CHECKED) + { + db->eno = ENOMEM; + return 0; /* signals an error to curl */ + } + db->buf = GNUNET_realloc (db->buf, + db->buf_size + msize); + buf = db->buf + db->buf_size; + memcpy (buf, bufptr, msize); + db->buf_size += msize; + return msize; +} + + +/** + * Obtain information about the final result about the + * HTTP download. If the download was successful, parses + * the JSON in the @a db and returns it. Also returns + * the HTTP @a response_code. If the download failed, + * the return value is NULL. The response code is set + * in any case, on download errors to zero. + * + * Calling this function also cleans up @a db. + * + * @param db download buffer + * @param eh CURL handle (to get the response code) + * @param[out] response_code set to the HTTP response code + * (or zero if we aborted the download, i.e. + * because the response was too big, or if + * the JSON we received was malformed). + * @return NULL if downloading a JSON reply failed + */ +json_t * +MAC_download_get_result (struct MAC_DownloadBuffer *db, + CURL *eh, + long *response_code) +{ + json_t *json; + json_error_t error; + + json = NULL; + if (0 == db->eno) + { + json = json_loadb (db->buf, + db->buf_size, + JSON_REJECT_DUPLICATES | JSON_DISABLE_EOF_CHECK, + &error); + if (NULL == json) + { + JSON_WARN (error); + *response_code = 0; + } + } + GNUNET_free_non_null (db->buf); + db->buf = NULL; + db->buf_size = 0; + if (NULL != json) + { + if (CURLE_OK != + curl_easy_getinfo (eh, + CURLINFO_RESPONSE_CODE, + response_code)) + { + /* unexpected error... */ + GNUNET_break (0); + *response_code = 0; + } + } + return json; +} + + /** * Initial global setup logic, specifically runs the Curl setup. */ diff --git a/src/mint-lib/mint_api_context.h b/src/mint-lib/mint_api_context.h index 235c32bd1..c545a3fe7 100644 --- a/src/mint-lib/mint_api_context.h +++ b/src/mint-lib/mint_api_context.h @@ -50,15 +50,20 @@ typedef void * instead use #MAC_easy_to_closure to extract the @a jcc_cls argument * from a valid @a eh afterwards. * + * This function modifies the CURL handle to add the + * "Content-Type: application/json" header if @a add_json is set. + * * @param ctx context to execute the job in * @param eh curl easy handle for the request, will * be executed AND cleaned up + * @param add_json add "application/json" content type header * @param jcc callback to invoke upon completion * @param jcc_cls closure for @a jcc */ struct MAC_Job * MAC_job_add (struct TALER_MINT_Context *ctx, CURL *eh, + int add_json, MAC_JobCompletionCallback jcc, void *jcc_cls); @@ -84,4 +89,81 @@ void MAC_job_cancel (struct MAC_Job *job); +/** + * Buffer data structure we use to buffer the HTTP download + * before giving it to the JSON parser. + */ +struct MAC_DownloadBuffer +{ + + /** + * Download buffer + */ + void *buf; + + /** + * The size of the download buffer + */ + size_t buf_size; + + /** + * Error code (based on libc errno) if we failed to download + * (i.e. response too large). + */ + int eno; + +}; + + +/** + * Callback used when downloading the reply to an HTTP request. + * Just appends all of the data to the `buf` in the + * `struct MAC_DownloadBuffer` for further processing. The size of + * the download is limited to #GNUNET_MAX_MALLOC_CHECKED, if + * the download exceeds this size, we abort with an error. + * + * Should be used by the various routines as the + * CURLOPT_WRITEFUNCTION. A `struct MAC_DownloadBuffer` needs to be + * passed to the CURLOPT_WRITEDATA. + * + * Afterwards, `eno` needs to be checked to ensure that the download + * completed correctly. + * + * @param bufptr data downloaded via HTTP + * @param size size of an item in @a bufptr + * @param nitems number of items in @a bufptr + * @param cls the `struct KeysRequest` + * @return number of bytes processed from @a bufptr + */ +size_t +MAC_download_cb (char *bufptr, + size_t size, + size_t nitems, + void *cls); + + +/** + * Obtain information about the final result about the + * HTTP download. If the download was successful, parses + * the JSON in the @a db and returns it. Also returns + * the HTTP @a response_code. If the download failed, + * the return value is NULL. The response code is set + * in any case, on download errors to zero. + * + * Calling this function also cleans up @a db. + * + * @param db download buffer + * @param eh CURL handle (to get the response code) + * @param[out] response_code set to the HTTP response code + * (or zero if we aborted the download, i.e. + * because the response was too big, or if + * the JSON we received was malformed). + * @return NULL if downloading a JSON reply failed + */ +json_t * +MAC_download_get_result (struct MAC_DownloadBuffer *db, + CURL *eh, + long *response_code); + + /* end of mint_api_context.h */ diff --git a/src/mint-lib/mint_api_deposit.c b/src/mint-lib/mint_api_deposit.c index 34915eaf1..7be88a887 100644 --- a/src/mint-lib/mint_api_deposit.c +++ b/src/mint-lib/mint_api_deposit.c @@ -32,15 +32,6 @@ #include "taler_signatures.h" -/** - * Print JSON parsing related error information - */ -#define JSON_WARN(error) \ - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, \ - "JSON parsing failed at %s:%u: %s (%s)\n", \ - __FILE__, __LINE__, error.text, error.source) - - /** * @brief A Deposit Handle */ @@ -67,11 +58,6 @@ struct TALER_MINT_DepositHandle */ struct MAC_Job *job; - /** - * HTTP headers for the request. - */ - struct curl_slist *headers; - /** * Function to call with the result. */ @@ -85,7 +71,7 @@ struct TALER_MINT_DepositHandle /** * Download buffer */ - void *buf; + struct MAC_DownloadBuffer db; /** * Information the mint should sign in response. @@ -102,17 +88,6 @@ struct TALER_MINT_DepositHandle */ struct TALER_Amount coin_value; - /** - * The size of the download buffer - */ - size_t buf_size; - - /** - * Error code (based on libc errno) if we failed to download - * (i.e. response too large). - */ - int eno; - }; @@ -321,35 +296,12 @@ handle_deposit_finished (void *cls, { struct TALER_MINT_DepositHandle *dh = cls; long response_code; - json_error_t error; json_t *json; dh->job = NULL; - json = NULL; - if (0 == dh->eno) - { - json = json_loadb (dh->buf, - dh->buf_size, - JSON_REJECT_DUPLICATES | JSON_DISABLE_EOF_CHECK, - &error); - if (NULL == json) - { - JSON_WARN (error); - response_code = 0; - } - } - if (NULL != json) - { - if (CURLE_OK != - curl_easy_getinfo (eh, - CURLINFO_RESPONSE_CODE, - &response_code)) - { - /* unexpected error... */ - GNUNET_break (0); - response_code = 0; - } - } + json = MAC_download_get_result (&dh->db, + eh, + &response_code); switch (response_code) { case 0: @@ -484,49 +436,6 @@ verify_signatures (const struct TALER_MINT_DenomPublicKey *dki, } -/** - * Callback used when downloading the reply to a /deposit request. - * Just appends all of the data to the `buf` in the - * `struct TALER_MINT_DepositHandle` for further processing. The size of - * the download is limited to #GNUNET_MAX_MALLOC_CHECKED, if - * the download exceeds this size, we abort with an error. - * - * @param bufptr data downloaded via HTTP - * @param size size of an item in @a bufptr - * @param nitems number of items in @a bufptr - * @param cls the `struct TALER_MINT_DepositHandle` - * @return number of bytes processed from @a bufptr - */ -static int -deposit_download_cb (char *bufptr, - size_t size, - size_t nitems, - void *cls) -{ - struct TALER_MINT_DepositHandle *dh = cls; - size_t msize; - void *buf; - - if (0 == size * nitems) - { - /* Nothing (left) to do */ - return 0; - } - msize = size * nitems; - if ( (msize + dh->buf_size) >= GNUNET_MAX_MALLOC_CHECKED) - { - dh->eno = ENOMEM; - return 0; /* signals an error to curl */ - } - dh->buf = GNUNET_realloc (dh->buf, - dh->buf_size + msize); - buf = dh->buf + dh->buf_size; - memcpy (buf, bufptr, msize); - dh->buf_size += msize; - return msize; -} - - /** * Submit a deposit permission to the mint and get the mint's response. * Note that while we return the response verbatim to the caller for @@ -624,7 +533,7 @@ TALER_MINT_deposit (struct TALER_MINT_Handle *mint, return NULL; } - deposit_obj = json_pack ("{s:o, s:o," /* f/wire */ + deposit_obj = json_pack ("{s:o, s:O," /* f/wire */ " s:o, s:o," /* H_wire, H_contract */ " s:o, s:o," /* coin_pub, denom_pub */ " s:o, s:o," /* ub_sig, timestamp */ @@ -691,21 +600,15 @@ TALER_MINT_deposit (struct TALER_MINT_Handle *mint, GNUNET_assert (CURLE_OK == curl_easy_setopt (eh, CURLOPT_WRITEFUNCTION, - &deposit_download_cb)); + &MAC_download_cb)); GNUNET_assert (CURLE_OK == curl_easy_setopt (eh, CURLOPT_WRITEDATA, - dh)); - GNUNET_assert (NULL != (dh->headers = - curl_slist_append (dh->headers, - "Content-Type: application/json"))); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_HTTPHEADER, - dh->headers)); + &dh->db)); ctx = MAH_handle_to_context (mint); dh->job = MAC_job_add (ctx, eh, + GNUNET_YES, &handle_deposit_finished, dh); return dh; @@ -726,7 +629,7 @@ TALER_MINT_deposit_cancel (struct TALER_MINT_DepositHandle *deposit) MAC_job_cancel (deposit->job); deposit->job = NULL; } - curl_slist_free_all (deposit->headers); + GNUNET_free_non_null (deposit->db.buf); GNUNET_free (deposit->url); GNUNET_free (deposit->json_enc); GNUNET_free (deposit); diff --git a/src/mint-lib/mint_api_handle.c b/src/mint-lib/mint_api_handle.c index 88a4f9331..f5e26ff15 100644 --- a/src/mint-lib/mint_api_handle.c +++ b/src/mint-lib/mint_api_handle.c @@ -44,14 +44,6 @@ function, __FILE__, __LINE__, curl_easy_strerror (code)); -/** - * Print JSON parsing related error information - */ -#define JSON_WARN(error) \ - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, \ - "JSON parsing failed at %s:%u: %s (%s)", \ - __FILE__, __LINE__, error.text, error.source) - /** * Stages of initialization for the `struct TALER_MINT_Handle` */ @@ -149,72 +141,13 @@ struct KeysRequest struct MAC_Job *job; /** - * Error buffer for Curl. Do we need this? + * Data structure for the download. */ - char emsg[CURL_ERROR_SIZE]; - - /** - * Download buffer - */ - void *buf; - - /** - * The size of the download buffer - */ - size_t buf_size; - - /** - * Error code (based on libc errno) if we failed to download - * (i.e. response too large). - */ - int eno; + struct MAC_DownloadBuffer db; }; -/** - * Callback used when downloading the reply to a /keys request. - * Just appends all of the data to the `buf` in the - * `struct KeysRequest` for further processing. The size of - * the download is limited to #GNUNET_MAX_MALLOC_CHECKED, if - * the download exceeds this size, we abort with an error. - * - * @param bufptr data downloaded via HTTP - * @param size size of an item in @a bufptr - * @param nitems number of items in @a bufptr - * @param cls the `struct KeysRequest` - * @return number of bytes processed from @a bufptr - */ -static size_t -keys_download_cb (char *bufptr, - size_t size, - size_t nitems, - void *cls) -{ - struct KeysRequest *kr = cls; - size_t msize; - void *buf; - - if (0 == size * nitems) - { - /* Nothing (left) to do */ - return 0; - } - msize = size * nitems; - if ( (msize + kr->buf_size) >= GNUNET_MAX_MALLOC_CHECKED) - { - kr->eno = ENOMEM; - return 0; /* signals an error to curl */ - } - kr->buf = GNUNET_realloc (kr->buf, - kr->buf_size + msize); - buf = kr->buf + kr->buf_size; - memcpy (buf, bufptr, msize); - kr->buf_size += msize; - return msize; -} - - /** * Release memory occupied by a keys request. * Note that this does not cancel the request @@ -225,7 +158,7 @@ keys_download_cb (char *bufptr, static void free_keys_request (struct KeysRequest *kr) { - GNUNET_free_non_null (kr->buf); + GNUNET_free_non_null (kr->db.buf); GNUNET_free (kr->url); GNUNET_free (kr); } @@ -493,7 +426,6 @@ decode_keys_json (json_t *resp_obj, hash_context)); } } - return GNUNET_OK; /* FIXME: parse the auditor keys (#3847) */ @@ -521,48 +453,6 @@ decode_keys_json (json_t *resp_obj, } -/** - * We have successfully received the reply to the /keys - * request from the mint. We now need to parse the reply - * and, if successful, store the resulting information - * in the `key_data` structure. - * - * @param kr key request with all of the data to parse - * and references to the `struct TALER_MINT_Handle` - * where we need to store the result - * @return #GNUNET_OK on success, - * #GNUNET_SYSERR on failure - */ -static int -parse_response_keys_get (struct KeysRequest *kr) -{ - json_t *resp_obj; - json_error_t error; - int ret; - - resp_obj = json_loadb (kr->buf, - kr->buf_size, - JSON_REJECT_DUPLICATES | JSON_DISABLE_EOF_CHECK, - &error); - if (NULL == resp_obj) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unable to parse received /keys data as JSON object\n"); - GNUNET_free_non_null (kr->buf); - kr->buf = NULL; - kr->buf_size = 0; - return GNUNET_SYSERR; - } - GNUNET_free_non_null (kr->buf); - kr->buf = NULL; - kr->buf_size = 0; - ret = decode_keys_json (resp_obj, - &kr->mint->key_data); - json_decref (resp_obj); - return ret; -} - - /** * Callback used when downloading the reply to a /keys request * is complete. @@ -576,35 +466,32 @@ keys_completed_cb (void *cls, { struct KeysRequest *kr = cls; struct TALER_MINT_Handle *mint = kr->mint; + json_t *resp_obj; long response_code; - /* FIXME: might want to check response code? */ - if (CURLE_OK != - curl_easy_getinfo (eh, - CURLINFO_RESPONSE_CODE, - &response_code)) - { - /* unexpected error... */ - GNUNET_break (0); - response_code = 0; - } + resp_obj = MAC_download_get_result (&kr->db, + eh, + &response_code); switch (response_code) { case 0: - kr->eno = 1; break; case MHD_HTTP_OK: + if ( (NULL == resp_obj) || + (GNUNET_OK != + decode_keys_json (resp_obj, + &kr->mint->key_data)) ) + response_code = 0; break; default: - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Mint returned status code %u for /keys\n", + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u\n", response_code); - kr->eno = 1; break; } + if (NULL != resp_obj) + json_decref (resp_obj); - if ( (0 != kr->eno) || - (GNUNET_OK != - parse_response_keys_get (kr)) ) + if (MHD_HTTP_OK != response_code) { mint->kr = NULL; free_keys_request (kr); @@ -722,20 +609,17 @@ TALER_MINT_connect (struct TALER_MINT_Context *ctx, curl_easy_setopt (c, CURLOPT_URL, kr->url)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (c, - CURLOPT_ERRORBUFFER, - kr->emsg)); GNUNET_assert (CURLE_OK == curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, - &keys_download_cb)); + &MAC_download_cb)); GNUNET_assert (CURLE_OK == curl_easy_setopt (c, CURLOPT_WRITEDATA, - kr)); + &kr->db)); kr->job = MAC_job_add (mint->ctx, c, + GNUNET_NO, &keys_completed_cb, kr); mint->kr = kr; @@ -751,6 +635,8 @@ TALER_MINT_connect (struct TALER_MINT_Context *ctx, void TALER_MINT_disconnect (struct TALER_MINT_Handle *mint) { + unsigned int i; + if (NULL != mint->kr) { MAC_job_cancel (mint->kr->job); @@ -760,6 +646,8 @@ TALER_MINT_disconnect (struct TALER_MINT_Handle *mint) GNUNET_array_grow (mint->key_data.sign_keys, mint->key_data.num_sign_keys, 0); + for (i=0;ikey_data.num_denom_keys;i++) + GNUNET_CRYPTO_rsa_public_key_free (mint->key_data.denom_keys[i].key.rsa_public_key); GNUNET_array_grow (mint->key_data.denom_keys, mint->key_data.num_denom_keys, 0); diff --git a/src/mint-lib/mint_api_withdraw.c b/src/mint-lib/mint_api_withdraw.c index 157d2db72..e7a1a61d4 100644 --- a/src/mint-lib/mint_api_withdraw.c +++ b/src/mint-lib/mint_api_withdraw.c @@ -31,15 +31,6 @@ #include "taler_signatures.h" -/** - * Print JSON parsing related error information - */ -#define JSON_WARN(error) \ - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, \ - "JSON parsing failed at %s:%u: %s (%s)\n", \ - __FILE__, __LINE__, error.text, error.source) - - /* ********************** /withdraw/status ********************** */ /** @@ -81,18 +72,7 @@ struct TALER_MINT_WithdrawStatusHandle /** * Download buffer */ - void *buf; - - /** - * The size of the download buffer - */ - size_t buf_size; - - /** - * Error code (based on libc errno) if we failed to download - * (i.e. response too large). - */ - int eno; + struct MAC_DownloadBuffer db; }; @@ -295,35 +275,12 @@ handle_withdraw_status_finished (void *cls, { struct TALER_MINT_WithdrawStatusHandle *wsh = cls; long response_code; - json_error_t error; json_t *json; wsh->job = NULL; - json = NULL; - if (0 == wsh->eno) - { - json = json_loadb (wsh->buf, - wsh->buf_size, - JSON_REJECT_DUPLICATES | JSON_DISABLE_EOF_CHECK, - &error); - if (NULL == json) - { - JSON_WARN (error); - response_code = 0; - } - } - if (NULL != json) - { - if (CURLE_OK != - curl_easy_getinfo (eh, - CURLINFO_RESPONSE_CODE, - &response_code)) - { - /* unexpected error... */ - GNUNET_break (0); - response_code = 0; - } - } + json = MAC_download_get_result (&wsh->db, + eh, + &response_code); switch (response_code) { case 0: @@ -404,6 +361,9 @@ handle_withdraw_status_finished (void *cls, 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; @@ -419,49 +379,6 @@ handle_withdraw_status_finished (void *cls, } -/** - * Callback used when downloading the reply to a /withdraw/status request. - * Just appends all of the data to the `buf` in the - * `struct TALER_MINT_WithdrawStatusHandle` for further processing. The size of - * the download is limited to #GNUNET_MAX_MALLOC_CHECKED, if - * the download exceeds this size, we abort with an error. - * - * @param bufptr data downloaded via HTTP - * @param size size of an item in @a bufptr - * @param nitems number of items in @a bufptr - * @param cls the `struct TALER_MINT_DepositHandle` - * @return number of bytes processed from @a bufptr - */ -static int -withdraw_status_download_cb (char *bufptr, - size_t size, - size_t nitems, - void *cls) -{ - struct TALER_MINT_WithdrawStatusHandle *wsh = cls; - size_t msize; - void *buf; - - if (0 == size * nitems) - { - /* Nothing (left) to do */ - return 0; - } - msize = size * nitems; - if ( (msize + wsh->buf_size) >= GNUNET_MAX_MALLOC_CHECKED) - { - wsh->eno = ENOMEM; - return 0; /* signals an error to curl */ - } - wsh->buf = GNUNET_realloc (wsh->buf, - wsh->buf_size + msize); - buf = wsh->buf + wsh->buf_size; - memcpy (buf, bufptr, msize); - wsh->buf_size += msize; - return msize; -} - - /** * Submit a request to obtain the transaction history of a reserve * from the mint. Note that while we return the full response to the @@ -519,14 +436,15 @@ TALER_MINT_withdraw_status (struct TALER_MINT_Handle *mint, GNUNET_assert (CURLE_OK == curl_easy_setopt (eh, CURLOPT_WRITEFUNCTION, - &withdraw_status_download_cb)); + &MAC_download_cb)); GNUNET_assert (CURLE_OK == curl_easy_setopt (eh, CURLOPT_WRITEDATA, - wsh)); + &wsh->db)); ctx = MAH_handle_to_context (mint); wsh->job = MAC_job_add (ctx, eh, + GNUNET_NO, &handle_withdraw_status_finished, wsh); return wsh; @@ -547,6 +465,7 @@ TALER_MINT_withdraw_status_cancel (struct TALER_MINT_WithdrawStatusHandle *wsh) MAC_job_cancel (wsh->job); wsh->job = NULL; } + GNUNET_free_non_null (wsh->db.buf); GNUNET_free (wsh->url); GNUNET_free (wsh); } @@ -580,11 +499,6 @@ struct TALER_MINT_WithdrawSignHandle */ struct MAC_Job *job; - /** - * HTTP headers for the request. - */ - struct curl_slist *headers; - /** * Function to call with the result. */ @@ -608,7 +522,7 @@ struct TALER_MINT_WithdrawSignHandle /** * Download buffer */ - void *buf; + struct MAC_DownloadBuffer db; /** * Hash of the public key of the coin we are signing. @@ -620,17 +534,6 @@ struct TALER_MINT_WithdrawSignHandle */ struct TALER_ReservePublicKeyP reserve_pub; - /** - * The size of the download buffer - */ - size_t buf_size; - - /** - * Error code (based on libc errno) if we failed to download - * (i.e. response too large). - */ - int eno; - }; @@ -797,33 +700,12 @@ handle_withdraw_sign_finished (void *cls, { struct TALER_MINT_WithdrawSignHandle *wsh = cls; long response_code; - json_error_t error; json_t *json; wsh->job = NULL; - json = NULL; - if (CURLE_OK != - curl_easy_getinfo (eh, - CURLINFO_RESPONSE_CODE, - &response_code)) - { - /* unexpected error... */ - GNUNET_break (0); - response_code = 0; - } - if ( (0 == wsh->eno) && - (0 != response_code) ) - { - json = json_loadb (wsh->buf, - wsh->buf_size, - JSON_REJECT_DUPLICATES | JSON_DISABLE_EOF_CHECK, - &error); - if (NULL == json) - { - JSON_WARN (error); - response_code = 0; - } - } + json = MAC_download_get_result (&wsh->db, + eh, + &response_code); switch (response_code) { case 0: @@ -870,6 +752,9 @@ handle_withdraw_sign_finished (void *cls, 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; @@ -884,49 +769,6 @@ handle_withdraw_sign_finished (void *cls, } -/** - * Callback used when downloading the reply to a /withdraw/sign request. - * Just appends all of the data to the `buf` in the - * `struct TALER_MINT_WithdrawSignHandle` for further processing. The size of - * the download is limited to #GNUNET_MAX_MALLOC_CHECKED, if - * the download exceeds this size, we abort with an error. - * - * @param bufptr data downloaded via HTTP - * @param size size of an item in @a bufptr - * @param nitems number of items in @a bufptr - * @param cls the `struct TALER_MINT_DepositHandle` - * @return number of bytes processed from @a bufptr - */ -static int -withdraw_sign_download_cb (char *bufptr, - size_t size, - size_t nitems, - void *cls) -{ - struct TALER_MINT_WithdrawSignHandle *wsh = cls; - size_t msize; - void *buf; - - if (0 == size * nitems) - { - /* Nothing (left) to do */ - return 0; - } - msize = size * nitems; - if ( (msize + wsh->buf_size) >= GNUNET_MAX_MALLOC_CHECKED) - { - wsh->eno = ENOMEM; - return 0; /* signals an error to curl */ - } - wsh->buf = GNUNET_realloc (wsh->buf, - wsh->buf_size + msize); - buf = wsh->buf + wsh->buf_size; - memcpy (buf, bufptr, msize); - wsh->buf_size += msize; - return msize; -} - - /** * Withdraw a coin from the mint using a /withdraw/sign request. Note * that to ensure that no money is lost in case of hardware failures, @@ -1045,21 +887,15 @@ TALER_MINT_withdraw_sign (struct TALER_MINT_Handle *mint, GNUNET_assert (CURLE_OK == curl_easy_setopt (eh, CURLOPT_WRITEFUNCTION, - &withdraw_sign_download_cb)); + &MAC_download_cb)); GNUNET_assert (CURLE_OK == curl_easy_setopt (eh, CURLOPT_WRITEDATA, - wsh)); - GNUNET_assert (NULL != (wsh->headers = - curl_slist_append (wsh->headers, - "Content-Type: application/json"))); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_HTTPHEADER, - wsh->headers)); + &wsh->db)); ctx = MAH_handle_to_context (mint); wsh->job = MAC_job_add (ctx, eh, + GNUNET_YES, &handle_withdraw_sign_finished, wsh); return wsh; @@ -1080,7 +916,7 @@ TALER_MINT_withdraw_sign_cancel (struct TALER_MINT_WithdrawSignHandle *sign) MAC_job_cancel (sign->job); sign->job = NULL; } - curl_slist_free_all (sign->headers); + GNUNET_free_non_null (sign->db.buf); GNUNET_free (sign->url); GNUNET_free (sign->json_enc); GNUNET_free (sign); diff --git a/src/mint/taler-mint-httpd_admin.c b/src/mint/taler-mint-httpd_admin.c index c757fd183..5fdfa58ee 100644 --- a/src/mint/taler-mint-httpd_admin.c +++ b/src/mint/taler-mint-httpd_admin.c @@ -146,6 +146,7 @@ TMH_ADMIN_handler_admin_add_incoming (struct TMH_RequestHandler *rh, wire)) { TMH_PARSE_release_data (spec); + json_decref (root); return TMH_RESPONSE_reply_arg_unknown (connection, "wire"); } diff --git a/src/mint/taler-mint-httpd_parsing.c b/src/mint/taler-mint-httpd_parsing.c index 8d7903eb5..78380f861 100644 --- a/src/mint/taler-mint-httpd_parsing.c +++ b/src/mint/taler-mint-httpd_parsing.c @@ -152,7 +152,6 @@ release_data (struct TMH_PARSE_FieldSpecification *spec, unsigned int spec_len) { unsigned int i; - void *ptr; for (i=0; i < spec_len; i++) { @@ -175,11 +174,15 @@ release_data (struct TMH_PARSE_FieldSpecification *spec, } break; case TMH_PARSE_JNC_RET_TYPED_JSON: - ptr = *(void **) spec[i].destination; - if (NULL != ptr) { - json_decref (ptr); - *(void**) spec[i].destination = NULL; + json_t *json; + + json = *(json_t **) spec[i].destination; + if (NULL != json) + { + json_decref (json); + *(json_t**) spec[i].destination = NULL; + } } break; case TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY: @@ -606,7 +609,9 @@ TMH_PARSE_navigate_json (struct MHD_Connection *connection, int typ = va_arg (argp, int); const json_t **r_json = va_arg (argp, const json_t **); - if ( (-1 != typ) && (json_typeof (root) != typ)) + if ( (NULL == root) || + ( (-1 != typ) && + (json_typeof (root) != typ)) ) { *r_json = NULL; ret = (MHD_YES == @@ -899,7 +904,7 @@ TMH_PARSE_json_data (struct MHD_Connection *connection, spec[i].field_name, TMH_PARSE_JNC_RET_TYPED_JSON, spec[i].type, - &spec[i].destination); + spec[i].destination); break; case TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY: ret = TMH_PARSE_navigate_json (connection, @@ -994,7 +999,7 @@ TMH_PARSE_member_uint64 (const char *field, * Generate line in parser specification for JSON object value. * * @param field name of the field - * @param jsonp address of pointer to JSON to initialize + * @param[out] jsonp address of pointer to JSON to initialize * @return corresponding field spec */ struct TMH_PARSE_FieldSpecification @@ -1002,7 +1007,8 @@ TMH_PARSE_member_object (const char *field, json_t **jsonp) { struct TMH_PARSE_FieldSpecification ret = - { field, (void **) jsonp, 0, NULL, TMH_PARSE_JNC_RET_TYPED_JSON, JSON_OBJECT }; + { field, jsonp, 0, NULL, TMH_PARSE_JNC_RET_TYPED_JSON, JSON_OBJECT }; + *jsonp = NULL; return ret; } @@ -1011,7 +1017,7 @@ TMH_PARSE_member_object (const char *field, * Generate line in parser specification for JSON array value. * * @param field name of the field - * @param jsonp address of JSON pointer to initialize + * @param[out] jsonp address of JSON pointer to initialize * @return corresponding field spec */ struct TMH_PARSE_FieldSpecification @@ -1020,6 +1026,7 @@ TMH_PARSE_member_array (const char *field, { struct TMH_PARSE_FieldSpecification ret = { field, jsonp, 0, NULL, TMH_PARSE_JNC_RET_TYPED_JSON, JSON_ARRAY }; + *jsonp = NULL; return ret; } @@ -1053,6 +1060,7 @@ TMH_PARSE_member_denomination_public_key (const char *field, { struct TMH_PARSE_FieldSpecification ret = { field, pk, 0, NULL, TMH_PARSE_JNC_RET_RSA_PUBLIC_KEY, 0 }; + pk->rsa_public_key = NULL; return ret; } @@ -1070,6 +1078,7 @@ TMH_PARSE_member_denomination_signature (const char *field, { struct TMH_PARSE_FieldSpecification ret = { field, sig, 0, NULL, TMH_PARSE_JNC_RET_RSA_SIGNATURE, 0 }; + sig->rsa_signature = NULL; return ret; } @@ -1087,6 +1096,7 @@ TMH_PARSE_member_amount (const char *field, { struct TMH_PARSE_FieldSpecification ret = { field, amount, sizeof(struct TALER_Amount), NULL, TMH_PARSE_JNC_RET_AMOUNT, 0 }; + memset (amount, 0, sizeof (struct TALER_Amount)); return ret; } @@ -1106,6 +1116,7 @@ TMH_PARSE_member_variable (const char *field, { struct TMH_PARSE_FieldSpecification ret = { field, ptr, 0, ptr_size, TMH_PARSE_JNC_RET_DATA_VAR, 0 }; + *ptr = NULL; return ret; }