diff options
author | Christian Grothoff <christian@grothoff.org> | 2019-11-29 10:52:45 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2019-11-29 10:52:45 +0100 |
commit | 636488c2797b498c8861bc6864539a63323b3608 (patch) | |
tree | 11b0f04aa31c40a0736babf5ee0a4d0d29682a32 | |
parent | 970e3fd4cb4a3f76d1bcf56e4cec668bcb828078 (diff) | |
parent | 785f5fb7dd5f8e4aa0258e3e72f519c77942cb7d (diff) |
merge error codes
61 files changed, 2705 insertions, 3468 deletions
diff --git a/.gitignore b/.gitignore index 5bb943a9d..5bb95cb46 100644 --- a/.gitignore +++ b/.gitignore @@ -59,6 +59,7 @@ src/exchange/test_taler_exchange_httpd_home/.local/share/taler/exchange/live-key src/exchange/test_taler_exchange_httpd_home/.local/share/taler/exchange/wirefees/ src/exchange-tools/taler-auditor-sign src/exchange-tools/taler-exchange-dbinit +src/exchange-tools/taler-exchange-tvg src/exchange-tools/taler-exchange-keycheck src/exchange-tools/taler-exchange-keyup src/exchange-tools/taler-exchange-wire diff --git a/configure.ac b/configure.ac index 44703bf1e..07fc2860b 100644 --- a/configure.ac +++ b/configure.ac @@ -550,6 +550,7 @@ AC_CONFIG_FILES([Makefile src/benchmark/Makefile src/include/Makefile src/json/Makefile + src/mhd/Makefile src/pq/Makefile src/util/Makefile src/util/taler-config diff --git a/src/Makefile.am b/src/Makefile.am index 38bf715fe..761b9c335 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -22,7 +22,7 @@ pkgcfg_DATA = \ EXTRA_DIST = \ taler.conf -SUBDIRS = include util wire json curl $(PQ_DIR) $(BANK_LIB) wire-plugins exchangedb exchange exchange-tools auditordb auditor +SUBDIRS = include util wire json curl $(PQ_DIR) mhd $(BANK_LIB) wire-plugins exchangedb exchange exchange-tools auditordb auditor if HAVE_LIBCURL SUBDIRS += lib benchmark else diff --git a/src/auditor/Makefile.am b/src/auditor/Makefile.am index e3600e20f..a1bb4d247 100644 --- a/src/auditor/Makefile.am +++ b/src/auditor/Makefile.am @@ -52,11 +52,10 @@ taler_auditor_httpd_SOURCES = \ taler-auditor-httpd_db.c taler-auditor-httpd_db.h \ taler-auditor-httpd_deposit-confirmation.c taler-auditor-httpd_deposit-confirmation.h \ taler-auditor-httpd_exchanges.c taler-auditor-httpd_exchanges.h \ - taler-auditor-httpd_mhd.c taler-auditor-httpd_mhd.h \ - taler-auditor-httpd_parsing.c taler-auditor-httpd_parsing.h \ - taler-auditor-httpd_responses.c taler-auditor-httpd_responses.h + taler-auditor-httpd_mhd.c taler-auditor-httpd_mhd.h taler_auditor_httpd_LDADD = \ $(LIBGCRYPT_LIBS) \ + $(top_builddir)/src/mhd/libtalermhd.la \ $(top_builddir)/src/util/libtalerutil.la \ $(top_builddir)/src/json/libtalerjson.la \ $(top_builddir)/src/wire/libtalerwire.la \ diff --git a/src/auditor/taler-auditor-httpd.c b/src/auditor/taler-auditor-httpd.c index e37b4a0e8..55a343776 100644 --- a/src/auditor/taler-auditor-httpd.c +++ b/src/auditor/taler-auditor-httpd.c @@ -27,11 +27,10 @@ #include <microhttpd.h> #include <pthread.h> #include <sys/resource.h> +#include "taler_mhd_lib.h" #include "taler_auditordb_lib.h" #include "taler-auditor-httpd_deposit-confirmation.h" #include "taler-auditor-httpd_exchanges.h" -#include "taler-auditor-httpd_parsing.h" -#include "taler-auditor-httpd_responses.h" #include "taler-auditor-httpd_mhd.h" #include "taler-auditor-httpd.h" @@ -291,7 +290,7 @@ handle_mhd_completion_callback (void *cls, { if (NULL == *con_cls) return; - TAH_PARSE_post_cleanup_callback (*con_cls); + TALER_MHD_parse_post_cleanup_callback (*con_cls); *con_cls = NULL; } @@ -332,9 +331,9 @@ handle_version (struct TAH_RequestHandler *rh, GNUNET_break (0); return MHD_NO; } - return TAH_RESPONSE_reply_json (connection, - ver, - MHD_HTTP_OK); + return TALER_MHD_reply_json (connection, + ver, + MHD_HTTP_OK); } @@ -384,7 +383,7 @@ handle_mhd_request (void *cls, &TAH_MHD_handler_static_response, MHD_HTTP_OK }, /* AGPL licensing page, redirect to source. As per the AGPL-license, every deployment is required to offer the user a download of the - source. We make this easy by including a redirect to the source + source. We make this easy by including a redirect t the source here. */ { "/agpl", MHD_HTTP_METHOD_GET, "text/plain", NULL, 0, @@ -392,11 +391,6 @@ handle_mhd_request (void *cls, { NULL, NULL, NULL, NULL, 0, 0 } }; - static struct TAH_RequestHandler h404 = { - "", NULL, "text/html", - "<html><title>404: not found</title></html>", 0, - &TAH_MHD_handler_static_response, MHD_HTTP_NOT_FOUND - }; struct TAH_RequestHandler *rh; GNUNET_log (GNUNET_ERROR_TYPE_INFO, @@ -419,127 +413,13 @@ handle_mhd_request (void *cls, upload_data, upload_data_size); } - return TAH_MHD_handler_static_response (&h404, - connection, - con_cls, - upload_data, - upload_data_size); -} - - -/** - * Parse the configuration to determine on which port - * or UNIX domain path we should run an HTTP service. - * - * @param section section of the configuration to parse ("auditor" or "auditor-admin") - * @param[out] rport set to the port number, or 0 for none - * @param[out] unix_path set to the UNIX path, or NULL for none - * @param[out] unix_mode set to the mode to be used for @a unix_path - * @return #GNUNET_OK on success - */ -static int -parse_port_config (const char *section, - uint16_t *rport, - char **unix_path, - mode_t *unix_mode) -{ - const char *choices[] = {"tcp", "unix"}; - const char *serve_type; - unsigned long long port; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_choice (cfg, - section, - "serve", - choices, - &serve_type)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - section, - "serve", - "serve type required"); - return GNUNET_SYSERR; - } - - if (0 == strcmp (serve_type, "tcp")) - { - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (cfg, - section, - "port", - &port)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - section, - "port", - "port number required"); - return GNUNET_SYSERR; - } - - if ( (0 == port) || - (port > UINT16_MAX) ) - { - fprintf (stderr, - "Invalid configuration (value out of range): %llu is not a valid port\n", - port); - return GNUNET_SYSERR; - } - *rport = (uint16_t) port; - *unix_path = NULL; - return GNUNET_OK; - } - if (0 == strcmp (serve_type, "unix")) - { - struct sockaddr_un s_un; - char *modestring; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (cfg, - section, - "unixpath", - unix_path)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - section, - "unixpath", - "unixpath required"); - return GNUNET_SYSERR; - } - if (strlen (*unix_path) >= sizeof (s_un.sun_path)) - { - fprintf (stderr, - "Invalid configuration: unix path too long\n"); - return GNUNET_SYSERR; - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - section, - "UNIXPATH_MODE", - &modestring)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - section, - "UNIXPATH_MODE"); - return GNUNET_SYSERR; - } - errno = 0; - *unix_mode = (mode_t) strtoul (modestring, NULL, 8); - if (0 != errno) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - section, - "UNIXPATH_MODE", - "must be octal number"); - GNUNET_free (modestring); - return GNUNET_SYSERR; - } - GNUNET_free (modestring); - return GNUNET_OK; - } - /* not reached */ - GNUNET_assert (0); - return GNUNET_SYSERR; +#define NOT_FOUND "<html><title>404: not found</title></html>" + return TALER_MHD_reply_static (connection, + MHD_HTTP_NOT_FOUND, + "text/html", + NOT_FOUND, + strlen (NOT_FOUND)); +#undef NOT_FOUND } @@ -562,10 +442,11 @@ auditor_serve_process_config () return GNUNET_SYSERR; } if (GNUNET_OK != - parse_port_config ("auditor", - &serve_port, - &serve_unixpath, - &unixpath_mode)) + TALER_MHD_parse_config (cfg, + "auditor", + &serve_port, + &serve_unixpath, + &unixpath_mode)) { return GNUNET_SYSERR; } @@ -641,141 +522,6 @@ auditor_serve_process_config () /** - * Function called for logging by MHD. - * - * @param cls closure, NULL - * @param fm format string (`printf()`-style) - * @param ap arguments to @a fm - */ -static void -handle_mhd_logs (void *cls, - const char *fm, - va_list ap) -{ - static int cache; - char buf[2048]; - - if (-1 == cache) - return; - if (0 == cache) - { - if (0 == - GNUNET_get_log_call_status (GNUNET_ERROR_TYPE_INFO, - "auditor-httpd", - __FILE__, - __FUNCTION__, - __LINE__)) - { - cache = -1; - return; - } - } - cache = 1; - vsnprintf (buf, - sizeof (buf), - fm, - ap); - GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_INFO, - "auditor-httpd", - "%s", - buf); -} - - -/** - * Open UNIX domain socket for listining at @a unix_path with - * permissions @a unix_mode. - * - * @param unix_path where to listen - * @param unix_mode access permissions to set - * @return -1 on error, otherwise the listen socket - */ -static int -open_unix_path (const char *unix_path, - mode_t unix_mode) -{ - struct GNUNET_NETWORK_Handle *nh; - struct sockaddr_un *un; - int fd; - - if (sizeof (un->sun_path) <= strlen (unix_path)) - { - fprintf (stderr, - "unixpath `%s' too long\n", - unix_path); - return -1; - } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Creating listen socket '%s' with mode %o\n", - unix_path, - unix_mode); - - if (GNUNET_OK != - GNUNET_DISK_directory_create_for_file (unix_path)) - { - GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, - "mkdir", - unix_path); - } - - un = GNUNET_new (struct sockaddr_un); - un->sun_family = AF_UNIX; - strncpy (un->sun_path, - unix_path, - sizeof (un->sun_path) - 1); - GNUNET_NETWORK_unix_precheck (un); - - if (NULL == (nh = GNUNET_NETWORK_socket_create (AF_UNIX, - SOCK_STREAM, - 0))) - { - fprintf (stderr, - "create failed for AF_UNIX\n"); - GNUNET_free (un); - return -1; - } - if (GNUNET_OK != - GNUNET_NETWORK_socket_bind (nh, - (void *) un, - sizeof (struct sockaddr_un))) - { - fprintf (stderr, - "bind failed for AF_UNIX\n"); - GNUNET_free (un); - GNUNET_NETWORK_socket_close (nh); - return -1; - } - GNUNET_free (un); - if (GNUNET_OK != - GNUNET_NETWORK_socket_listen (nh, - UNIX_BACKLOG)) - { - fprintf (stderr, - "listen failed for AF_UNIX\n"); - GNUNET_NETWORK_socket_close (nh); - return -1; - } - - if (0 != chmod (unix_path, - unix_mode)) - { - fprintf (stderr, - "chmod failed: %s\n", - strerror (errno)); - GNUNET_NETWORK_socket_close (nh); - return -1; - } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "set socket '%s' to mode %o\n", - unix_path, - unix_mode); - fd = GNUNET_NETWORK_get_fd (nh); - GNUNET_NETWORK_socket_free_memory_only_ (nh); - return fd; -} - - -/** * The main function of the taler-auditor-httpd server ("the auditor"). * * @param argc number of arguments from the command line @@ -811,12 +557,17 @@ main (int argc, const char *listen_pid; const char *listen_fds; int fh = -1; + enum TALER_MHD_GlobalOptions go; if (0 >= GNUNET_GETOPT_run ("taler-auditor-httpd", options, argc, argv)) return 1; + go = TALER_MHD_GO_NONE; + if (TAH_auditor_connection_close) + go |= TALER_MHD_GO_FORCE_CONNECTION_CLOSE; + TALER_MHD_setup (go); GNUNET_assert (GNUNET_OK == GNUNET_log_setup ("taler-auditor-httpd", (NULL == loglev) ? "INFO" : loglev, @@ -877,8 +628,8 @@ main (int argc, if ( (-1 == fh) && (NULL != serve_unixpath) ) { - fh = open_unix_path (serve_unixpath, - unixpath_mode); + fh = TALER_MHD_open_unix_path (serve_unixpath, + unixpath_mode); if (-1 == fh) return 1; } @@ -894,7 +645,8 @@ main (int argc, MHD_OPTION_THREAD_POOL_SIZE, (unsigned int) 32, MHD_OPTION_LISTEN_BACKLOG_SIZE, (unsigned int) 1024, MHD_OPTION_LISTEN_SOCKET, fh, - MHD_OPTION_EXTERNAL_LOGGER, &handle_mhd_logs, NULL, + MHD_OPTION_EXTERNAL_LOGGER, &TALER_MHD_handle_logs, + NULL, MHD_OPTION_NOTIFY_COMPLETED, &handle_mhd_completion_callback, NULL, MHD_OPTION_CONNECTION_TIMEOUT, connection_timeout, diff --git a/src/auditor/taler-auditor-httpd_db.c b/src/auditor/taler-auditor-httpd_db.c index e0ab8f2e1..3433e9a9f 100644 --- a/src/auditor/taler-auditor-httpd_db.c +++ b/src/auditor/taler-auditor-httpd_db.c @@ -23,8 +23,9 @@ #include <jansson.h> #include <gnunet/gnunet_json_lib.h> #include "taler_json_lib.h" +#include "taler_mhd_lib.h" #include "taler-auditor-httpd_db.h" -#include "taler-auditor-httpd_responses.h" +#include "taler-auditor-httpd.h" /** @@ -63,8 +64,10 @@ TAH_DB_run_transaction (struct MHD_Connection *connection, { GNUNET_break (0); if (NULL != mhd_ret) - *mhd_ret = TAH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_DB_SETUP_FAILED); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_DB_SETUP_FAILED, + "failed to establish session with database"); return GNUNET_SYSERR; } // TAH_plugin->preflight (TAH_plugin->cls, session); // FIXME: needed? @@ -79,8 +82,10 @@ TAH_DB_run_transaction (struct MHD_Connection *connection, { GNUNET_break (0); if (NULL != mhd_ret) - *mhd_ret = TAH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_DB_START_FAILED); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_DB_START_FAILED, + "failed to begin transaction"); return GNUNET_SYSERR; } qs = cb (cb_cls, @@ -98,8 +103,10 @@ TAH_DB_run_transaction (struct MHD_Connection *connection, if (GNUNET_DB_STATUS_HARD_ERROR == qs) { if (NULL != mhd_ret) - *mhd_ret = TAH_RESPONSE_reply_commit_error (connection, - TALER_EC_DB_COMMIT_FAILED_HARD); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_DB_COMMIT_FAILED_HARD, + "failed to commit transaction"); return GNUNET_SYSERR; } /* make sure callback did not violate invariants! */ @@ -112,8 +119,10 @@ TAH_DB_run_transaction (struct MHD_Connection *connection, name, MAX_TRANSACTION_COMMIT_RETRIES); if (NULL != mhd_ret) - *mhd_ret = TAH_RESPONSE_reply_commit_error (connection, - TALER_EC_DB_COMMIT_FAILED_ON_RETRY); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_DB_COMMIT_FAILED_ON_RETRY, + "transaction repeatedly failed to serialize"); return GNUNET_SYSERR; } diff --git a/src/auditor/taler-auditor-httpd_deposit-confirmation.c b/src/auditor/taler-auditor-httpd_deposit-confirmation.c index 2b73a910a..0a121fdae 100644 --- a/src/auditor/taler-auditor-httpd_deposit-confirmation.c +++ b/src/auditor/taler-auditor-httpd_deposit-confirmation.c @@ -27,11 +27,10 @@ #include <microhttpd.h> #include <pthread.h> #include "taler_json_lib.h" +#include "taler_mhd_lib.h" #include "taler-auditor-httpd.h" #include "taler-auditor-httpd_db.h" #include "taler-auditor-httpd_deposit-confirmation.h" -#include "taler-auditor-httpd_parsing.h" -#include "taler-auditor-httpd_responses.h" /** @@ -43,10 +42,10 @@ static int reply_deposit_confirmation_success (struct MHD_Connection *connection) { - return TAH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:s}", - "status", "DEPOSIT_CONFIRMATION_OK"); + return TALER_MHD_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:s}", + "status", "DEPOSIT_CONFIRMATION_OK"); } @@ -74,8 +73,10 @@ store_exchange_signing_key_transaction (void *cls, if (GNUNET_DB_STATUS_HARD_ERROR == qs) { TALER_LOG_WARNING ("Failed to store exchange signing key in database\n"); - *mhd_ret = TAH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_AUDITOR_EXCHANGE_STORE_DB_ERROR); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_AUDITOR_EXCHANGE_STORE_DB_ERROR, + "failed to persist exchange signing key"); } return qs; } @@ -111,8 +112,10 @@ deposit_confirmation_transaction (void *cls, { TALER_LOG_WARNING ( "Failed to store /deposit-confirmation information in database\n"); - *mhd_ret = TAH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_DEPOSIT_CONFIRMATION_STORE_DB_ERROR); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_DEPOSIT_CONFIRMATION_STORE_DB_ERROR, + "failed to persist deposit-confirmation data"); } return qs; } @@ -155,9 +158,10 @@ verify_and_execute_deposit_confirmation (struct MHD_Connection *connection, &es->master_public_key.eddsa_pub)) { TALER_LOG_WARNING ("Invalid signature on exchange signing key\n"); - return TAH_RESPONSE_reply_signature_invalid (connection, - TALER_EC_DEPOSIT_CONFIRMATION_SIGNATURE_INVALID, - "master_sig"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_FORBIDDEN, + TALER_EC_DEPOSIT_CONFIRMATION_SIGNATURE_INVALID, + "master_sig"); } /* execute transaction */ @@ -187,9 +191,10 @@ verify_and_execute_deposit_confirmation (struct MHD_Connection *connection, &dc->exchange_pub.eddsa_pub)) { TALER_LOG_WARNING ("Invalid signature on /deposit-confirmation request\n"); - return TAH_RESPONSE_reply_signature_invalid (connection, - TALER_EC_DEPOSIT_CONFIRMATION_SIGNATURE_INVALID, - "exchange_sig"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_FORBIDDEN, + TALER_EC_DEPOSIT_CONFIRMATION_SIGNATURE_INVALID, + "exchange_sig"); } /* execute transaction */ @@ -248,19 +253,19 @@ TAH_DEPOSIT_CONFIRMATION_handler (struct TAH_RequestHandler *rh, GNUNET_JSON_spec_end () }; - res = TAH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &json); + res = TALER_MHD_parse_post_json (connection, + connection_cls, + upload_data, + upload_data_size, + &json); if (GNUNET_SYSERR == res) return MHD_NO; if ( (GNUNET_NO == res) || (NULL == json) ) return MHD_YES; - res = TAH_PARSE_json_data (connection, - json, - spec); + res = TALER_MHD_parse_json_data (connection, + json, + spec); json_decref (json); es.exchange_pub = dc.exchange_pub; /* used twice! */ dc.master_public_key = es.master_public_key; diff --git a/src/auditor/taler-auditor-httpd_exchanges.c b/src/auditor/taler-auditor-httpd_exchanges.c index 881c45a23..3c6bfe68f 100644 --- a/src/auditor/taler-auditor-httpd_exchanges.c +++ b/src/auditor/taler-auditor-httpd_exchanges.c @@ -25,11 +25,10 @@ #include <microhttpd.h> #include <pthread.h> #include "taler_json_lib.h" +#include "taler_mhd_lib.h" #include "taler-auditor-httpd.h" #include "taler-auditor-httpd_db.h" #include "taler-auditor-httpd_exchanges.h" -#include "taler-auditor-httpd_parsing.h" -#include "taler-auditor-httpd_responses.h" /** @@ -43,10 +42,10 @@ static int reply_exchanges_success (struct MHD_Connection *connection, json_t *ja) { - return TAH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:o}", - "exchanges", ja); + return TALER_MHD_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:o}", + "exchanges", ja); } @@ -108,8 +107,10 @@ list_exchanges (void *cls, if (GNUNET_DB_STATUS_HARD_ERROR == qs) { TALER_LOG_WARNING ("Failed to handle /exchanges in database\n"); - *mhd_ret = TAH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_LIST_EXCHANGES_DB_ERROR); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_LIST_EXCHANGES_DB_ERROR, + "Could not fetch exchange list from database"); } return qs; } @@ -148,4 +149,4 @@ TAH_EXCHANGES_handler (struct TAH_RequestHandler *rh, } -/* end of taler-auditor-httpd_deposit-confirmation.c */ +/* end of taler-auditor-httpd_exchanges.c */ diff --git a/src/auditor/taler-auditor-httpd_mhd.c b/src/auditor/taler-auditor-httpd_mhd.c index 5f13691f5..01927469e 100644 --- a/src/auditor/taler-auditor-httpd_mhd.c +++ b/src/auditor/taler-auditor-httpd_mhd.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014 GNUnet e.V. + Copyright (C) 2014-2019 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 @@ -28,7 +28,7 @@ #include <jansson.h> #include <microhttpd.h> #include <pthread.h> -#include "taler-auditor-httpd_responses.h" +#include "taler_mhd_lib.h" #include "taler-auditor-httpd.h" #include "taler-auditor-httpd_mhd.h" @@ -53,6 +53,9 @@ TAH_MHD_handler_static_response (struct TAH_RequestHandler *rh, struct MHD_Response *response; int ret; + (void) connection_cls; + (void) upload_data; + (void) upload_data_size; if (0 == rh->data_size) rh->data_size = strlen ((const char *) rh->data); response = MHD_create_response_from_buffer (rh->data_size, @@ -63,7 +66,7 @@ TAH_MHD_handler_static_response (struct TAH_RequestHandler *rh, GNUNET_break (0); return MHD_NO; } - TAH_RESPONSE_add_global_headers (response); + TALER_MHD_add_global_headers (response); if (NULL != rh->mime_type) (void) MHD_add_response_header (response, MHD_HTTP_HEADER_CONTENT_TYPE, @@ -94,38 +97,12 @@ TAH_MHD_handler_agpl_redirect (struct TAH_RequestHandler *rh, const char *upload_data, size_t *upload_data_size) { - const char *agpl = - "This server is licensed under the Affero GPL. You will now be redirected to the source code."; - struct MHD_Response *response; - int ret; - - response = MHD_create_response_from_buffer (strlen (agpl), - (void *) agpl, - MHD_RESPMEM_PERSISTENT); - if (NULL == response) - { - GNUNET_break (0); - return MHD_NO; - } - TAH_RESPONSE_add_global_headers (response); - if (NULL != rh->mime_type) - (void) MHD_add_response_header (response, - MHD_HTTP_HEADER_CONTENT_TYPE, - rh->mime_type); - if (MHD_NO == - MHD_add_response_header (response, - MHD_HTTP_HEADER_LOCATION, - "http://www.git.taler.net/?p=auditor.git")) - { - GNUNET_break (0); - MHD_destroy_response (response); - return MHD_NO; - } - ret = MHD_queue_response (connection, - rh->response_code, - response); - MHD_destroy_response (response); - return ret; + (void) rh; + (void) connection_cls; + (void) upload_data; + (void) upload_data_size; + return TALER_MHD_reply_agpl (connection, + "http://www.git.taler.net/?p=exchange.git"); } @@ -147,11 +124,11 @@ TAH_MHD_handler_send_json_pack_error (struct TAH_RequestHandler *rh, const char *upload_data, size_t *upload_data_size) { - return TAH_RESPONSE_reply_json_pack (connection, - rh->response_code, - "{s:s}", - "error", - rh->data); + return TALER_MHD_reply_json_pack (connection, + rh->response_code, + "{s:s}", + "error", + rh->data); } diff --git a/src/auditor/taler-auditor-httpd_parsing.c b/src/auditor/taler-auditor-httpd_parsing.c deleted file mode 100644 index fb707c88f..000000000 --- a/src/auditor/taler-auditor-httpd_parsing.c +++ /dev/null @@ -1,284 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015, 2016 GNUnet e.V. - - 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 - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> -*/ - -/** - * @file taler-auditor-httpd_parsing.c - * @brief functions to parse incoming requests (MHD arguments and JSON snippets) - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ - -#include "platform.h" -#include <gnunet/gnunet_util_lib.h> -#include <gnunet/gnunet_json_lib.h> -#include "taler_json_lib.h" -#include "taler-auditor-httpd_parsing.h" -#include "taler-auditor-httpd_responses.h" - - -/** - * Maximum POST request size. - */ -#define REQUEST_BUFFER_MAX (1024 * 1024) - - -/** - * Process a POST request containing a JSON object. This function - * realizes an MHD POST processor that will (incrementally) process - * JSON data uploaded to the HTTP server. It will store the required - * state in the @a con_cls, which must be cleaned up using - * #TAH_PARSE_post_cleanup_callback(). - * - * @param connection the MHD connection - * @param con_cls the closure (points to a `struct Buffer *`) - * @param upload_data the POST data - * @param upload_data_size number of bytes in @a upload_data - * @param json the JSON object for a completed request - * @return - * #GNUNET_YES if json object was parsed or at least - * may be parsed in the future (call again); - * `*json` will be NULL if we need to be called again, - * and non-NULL if we are done. - * #GNUNET_NO is request incomplete or invalid - * (error message was generated) - * #GNUNET_SYSERR on internal error - * (we could not even queue an error message, - * close HTTP session with MHD_NO) - */ -int -TAH_PARSE_post_json (struct MHD_Connection *connection, - void **con_cls, - const char *upload_data, - size_t *upload_data_size, - json_t **json) -{ - enum GNUNET_JSON_PostResult pr; - - pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX, - connection, - con_cls, - upload_data, - upload_data_size, - json); - switch (pr) - { - case GNUNET_JSON_PR_OUT_OF_MEMORY: - return (MHD_NO == - TAH_RESPONSE_reply_internal_error (connection, - TALER_EC_PARSER_OUT_OF_MEMORY, - "out of memory")) - ? GNUNET_SYSERR : GNUNET_NO; - case GNUNET_JSON_PR_CONTINUE: - return GNUNET_YES; - case GNUNET_JSON_PR_REQUEST_TOO_LARGE: - return (MHD_NO == - TAH_RESPONSE_reply_request_too_large (connection)) - ? GNUNET_SYSERR : GNUNET_NO; - case GNUNET_JSON_PR_JSON_INVALID: - return (MHD_YES == - TAH_RESPONSE_reply_invalid_json (connection)) - ? GNUNET_NO : GNUNET_SYSERR; - case GNUNET_JSON_PR_SUCCESS: - GNUNET_break (NULL != *json); - return GNUNET_YES; - } - /* this should never happen */ - GNUNET_break (0); - return GNUNET_SYSERR; -} - - -/** - * Function called whenever we are done with a request - * to clean up our state. - * - * @param con_cls value as it was left by - * #TAH_PARSE_post_json(), to be cleaned up - */ -void -TAH_PARSE_post_cleanup_callback (void *con_cls) -{ - GNUNET_JSON_post_parser_cleanup (con_cls); -} - - -/** - * Extract base32crockford encoded data from request. - * - * Queues an error response to the connection if the parameter is - * missing or invalid. - * - * @param connection the MHD connection - * @param param_name the name of the parameter with the key - * @param[out] out_data pointer to store the result - * @param out_size expected size of data - * @return - * #GNUNET_YES if the the argument is present - * #GNUNET_NO if the argument is absent or malformed - * #GNUNET_SYSERR on internal error (error response could not be sent) - */ -int -TAH_PARSE_mhd_request_arg_data (struct MHD_Connection *connection, - const char *param_name, - void *out_data, - size_t out_size) -{ - const char *str; - - str = MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, - param_name); - if (NULL == str) - { - return (MHD_NO == - TAH_RESPONSE_reply_arg_missing (connection, - TALER_EC_PARAMETER_MISSING, - param_name)) - ? GNUNET_SYSERR : GNUNET_NO; - } - if (GNUNET_OK != - GNUNET_STRINGS_string_to_data (str, - strlen (str), - out_data, - out_size)) - return (MHD_NO == - TAH_RESPONSE_reply_arg_invalid (connection, - TALER_EC_PARAMETER_MALFORMED, - param_name)) - ? GNUNET_SYSERR : GNUNET_NO; - return GNUNET_OK; -} - - -/** - * Parse JSON object into components based on the given field - * specification. Generates error response on parse errors. - * - * @param connection the connection to send an error response to - * @param root the JSON node to start the navigation at. - * @param[in,out] spec field specification for the parser - * @return - * #GNUNET_YES if navigation was successful (caller is responsible - * for freeing allocated variable-size data using - * GNUNET_JSON_parse_free() when done) - * #GNUNET_NO if json is malformed, error response was generated - * #GNUNET_SYSERR on internal error - */ -int -TAH_PARSE_json_data (struct MHD_Connection *connection, - const json_t *root, - struct GNUNET_JSON_Specification *spec) -{ - int ret; - const char *error_json_name; - unsigned int error_line; - - ret = GNUNET_JSON_parse (root, - spec, - &error_json_name, - &error_line); - if (GNUNET_SYSERR == ret) - { - if (NULL == error_json_name) - error_json_name = "<no field>"; - ret = (MHD_YES == - TAH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:I, s:s, s:I}", - "error", "parse error", - "code", - (json_int_t) - TALER_EC_JSON_INVALID_WITH_DETAILS, - "field", error_json_name, - "line", (json_int_t) error_line)) - ? GNUNET_NO : GNUNET_SYSERR; - return ret; - } - return GNUNET_YES; -} - - -/** - * Parse JSON array into components based on the given field - * specification. Generates error response on parse errors. - * - * @param connection the connection to send an error response to - * @param root the JSON node to start the navigation at. - * @param[in,out] spec field specification for the parser - * @param ... -1-terminated list of array offsets of type 'int' - * @return - * #GNUNET_YES if navigation was successful (caller is responsible - * for freeing allocated variable-size data using - * GNUNET_JSON_parse_free() when done) - * #GNUNET_NO if json is malformed, error response was generated - * #GNUNET_SYSERR on internal error - */ -int -TAH_PARSE_json_array (struct MHD_Connection *connection, - const json_t *root, - struct GNUNET_JSON_Specification *spec, - ...) -{ - int ret; - const char *error_json_name; - unsigned int error_line; - va_list ap; - json_int_t dim; - - va_start (ap, spec); - dim = 0; - while ( (-1 != (ret = va_arg (ap, int))) && - (NULL != root) ) - { - dim++; - root = json_array_get (root, ret); - } - va_end (ap); - if (NULL == root) - { - ret = (MHD_YES == - TAH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:I}", - "error", "parse error", - "dimension", dim)) - ? GNUNET_NO : GNUNET_SYSERR; - return ret; - } - ret = GNUNET_JSON_parse (root, - spec, - &error_json_name, - &error_line); - if (GNUNET_SYSERR == ret) - { - if (NULL == error_json_name) - error_json_name = "<no field>"; - ret = (MHD_YES == - TAH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:s, s:I}", - "error", "parse error", - "field", error_json_name, - "line", (json_int_t) error_line)) - ? GNUNET_NO : GNUNET_SYSERR; - return ret; - } - return GNUNET_YES; -} - - -/* end of taler-auditor-httpd_parsing.c */ diff --git a/src/auditor/taler-auditor-httpd_parsing.h b/src/auditor/taler-auditor-httpd_parsing.h deleted file mode 100644 index 7df76ef54..000000000 --- a/src/auditor/taler-auditor-httpd_parsing.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015, 2016 GNUnet e.V. - - 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 - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-auditor-httpd_parsing.h - * @brief functions to parse incoming requests - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#ifndef TALER_AUDITOR_HTTPD_PARSING_H -#define TALER_AUDITOR_HTTPD_PARSING_H - -#include <microhttpd.h> -#include <jansson.h> -#include "taler_util.h" -#include "taler_json_lib.h" - - -/** - * Process a POST request containing a JSON object. This - * function realizes an MHD POST processor that will - * (incrementally) process JSON data uploaded to the HTTP - * server. It will store the required state in the - * "connection_cls", which must be cleaned up using - * #TAH_PARSE_post_cleanup_callback(). - * - * @param connection the MHD connection - * @param con_cls the closure (points to a `struct Buffer *`) - * @param upload_data the POST data - * @param upload_data_size number of bytes in @a upload_data - * @param json the JSON object for a completed request - * @return - * #GNUNET_YES if json object was parsed or at least - * may be parsed in the future (call again); - * `*json` will be NULL if we need to be called again, - * and non-NULL if we are done. - * #GNUNET_NO is request incomplete or invalid - * (error message was generated) - * #GNUNET_SYSERR on internal error - * (we could not even queue an error message, - * close HTTP session with MHD_NO) - */ -int -TAH_PARSE_post_json (struct MHD_Connection *connection, - void **con_cls, - const char *upload_data, - size_t *upload_data_size, - json_t **json); - - -/** - * Function called whenever we are done with a request - * to clean up our state. - * - * @param con_cls value as it was left by - * #TAH_PARSE_post_json(), to be cleaned up - */ -void -TAH_PARSE_post_cleanup_callback (void *con_cls); - - -/** - * Parse JSON object into components based on the given field - * specification. - * - * @param connection the connection to send an error response to - * @param root the JSON node to start the navigation at. - * @param spec field specification for the parser - * @return - * #GNUNET_YES if navigation was successful (caller is responsible - * for freeing allocated variable-size data using - * GNUNET_JSON_parse_free() when done) - * #GNUNET_NO if json is malformed, error response was generated - * #GNUNET_SYSERR on internal error - */ -int -TAH_PARSE_json_data (struct MHD_Connection *connection, - const json_t *root, - struct GNUNET_JSON_Specification *spec); - - -/** - * Parse JSON array into components based on the given field - * specification. Generates error response on parse errors. - * - * @param connection the connection to send an error response to - * @param root the JSON node to start the navigation at. - * @param[in,out] spec field specification for the parser - * @param ... -1-terminated list of array offsets of type 'int' - * @return - * #GNUNET_YES if navigation was successful (caller is responsible - * for freeing allocated variable-size data using - * GNUNET_JSON_parse_free() when done) - * #GNUNET_NO if json is malformed, error response was generated - * #GNUNET_SYSERR on internal error - */ -int -TAH_PARSE_json_array (struct MHD_Connection *connection, - const json_t *root, - struct GNUNET_JSON_Specification *spec, - ...); - - -/** - * Extraxt fixed-size base32crockford encoded data from request. - * - * Queues an error response to the connection if the parameter is missing or - * invalid. - * - * @param connection the MHD connection - * @param param_name the name of the parameter with the key - * @param[out] out_data pointer to store the result - * @param out_size expected size of @a out_data - * @return - * #GNUNET_YES if the the argument is present - * #GNUNET_NO if the argument is absent or malformed - * #GNUNET_SYSERR on internal error (error response could not be sent) - */ -int -TAH_PARSE_mhd_request_arg_data (struct MHD_Connection *connection, - const char *param_name, - void *out_data, - size_t out_size); - - -#endif /* TALER_AUDITOR_HTTPD_PARSING_H */ diff --git a/src/auditor/taler-auditor-httpd_responses.c b/src/auditor/taler-auditor-httpd_responses.c deleted file mode 100644 index 4c7b429e3..000000000 --- a/src/auditor/taler-auditor-httpd_responses.c +++ /dev/null @@ -1,480 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2017 Inria & GNUnet e.V. - - 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 - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-exchange-httpd_responses.c - * @brief API for generating genric replies of the exchange; these - * functions are called TAH_RESPONSE_reply_ and they generate - * and queue MHD response objects for a given connection. - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#include "platform.h" -#include <zlib.h> -#include "taler-auditor-httpd_responses.h" -#include "taler_util.h" -#include "taler_json_lib.h" - - -/** - * Add headers we want to return in every response. - * Useful for testing, like if we want to always close - * connections. - * - * @param response response to modify - */ -void -TAH_RESPONSE_add_global_headers (struct MHD_Response *response) -{ - if (TAH_auditor_connection_close) - GNUNET_break (MHD_YES == - MHD_add_response_header (response, - MHD_HTTP_HEADER_CONNECTION, - "close")); -} - - -/** - * Is HTTP body deflate compression supported by the client? - * - * @param connection connection to check - * @return #MHD_YES if 'deflate' compression is allowed - * - * Note that right now we're ignoring q-values, which is technically - * not correct, and also do not support "*" anywhere but in a line by - * itself. This should eventually be fixed, see also - * https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html - */ -int -TAH_RESPONSE_can_compress (struct MHD_Connection *connection) -{ - const char *ae; - const char *de; - - ae = MHD_lookup_connection_value (connection, - MHD_HEADER_KIND, - MHD_HTTP_HEADER_ACCEPT_ENCODING); - if (NULL == ae) - return MHD_NO; - if (0 == strcmp (ae, - "*")) - return MHD_YES; - de = strstr (ae, - "deflate"); - if (NULL == de) - return MHD_NO; - if ( ( (de == ae) || - (de[-1] == ',') || - (de[-1] == ' ') ) && - ( (de[strlen ("deflate")] == '\0') || - (de[strlen ("deflate")] == ',') || - (de[strlen ("deflate")] == ';') ) ) - return MHD_YES; - return MHD_NO; -} - - -/** - * Try to compress a response body. Updates @a buf and @a buf_size. - * - * @param[in,out] buf pointer to body to compress - * @param[in,out] buf_size pointer to initial size of @a buf - * @return #MHD_YES if @a buf was compressed - */ -int -TAH_RESPONSE_body_compress (void **buf, - size_t *buf_size) -{ - Bytef *cbuf; - uLongf cbuf_size; - int ret; - - cbuf_size = compressBound (*buf_size); - cbuf = malloc (cbuf_size); - if (NULL == cbuf) - return MHD_NO; - ret = compress (cbuf, - &cbuf_size, - (const Bytef *) *buf, - *buf_size); - if ( (Z_OK != ret) || - (cbuf_size >= *buf_size) ) - { - /* compression failed */ - free (cbuf); - return MHD_NO; - } - free (*buf); - *buf = (void *) cbuf; - *buf_size = (size_t) cbuf_size; - return MHD_YES; -} - - -/** - * Send JSON object as response. - * - * @param connection the MHD connection - * @param json the json object - * @param response_code the http response code - * @return MHD result code - */ -int -TAH_RESPONSE_reply_json (struct MHD_Connection *connection, - const json_t *json, - unsigned int response_code) -{ - struct MHD_Response *resp; - void *json_str; - size_t json_len; - int ret; - int comp; - - json_str = json_dumps (json, - JSON_INDENT (2)); - if (NULL == json_str) - { - /** - * This log helps to figure out which - * function called this one and assert-failed. - */ - TALER_LOG_ERROR ("Aborting json-packing for HTTP code: %u\n", - response_code); - - GNUNET_assert (0); - return MHD_NO; - } - json_len = strlen (json_str); - /* try to compress the body */ - comp = MHD_NO; - if (MHD_YES == - TAH_RESPONSE_can_compress (connection)) - comp = TAH_RESPONSE_body_compress (&json_str, - &json_len); - resp = MHD_create_response_from_buffer (json_len, - json_str, - MHD_RESPMEM_MUST_FREE); - if (NULL == resp) - { - free (json_str); - GNUNET_break (0); - return MHD_NO; - } - TAH_RESPONSE_add_global_headers (resp); - (void) MHD_add_response_header (resp, - MHD_HTTP_HEADER_CONTENT_TYPE, - "application/json"); - if (MHD_YES == comp) - { - /* Need to indicate to client that body is compressed */ - if (MHD_NO == - MHD_add_response_header (resp, - MHD_HTTP_HEADER_CONTENT_ENCODING, - "deflate")) - { - GNUNET_break (0); - MHD_destroy_response (resp); - return MHD_NO; - } - } - ret = MHD_queue_response (connection, - response_code, - resp); - MHD_destroy_response (resp); - return ret; -} - - -/** - * Function to call to handle the request by building a JSON - * reply from a format string and varargs. - * - * @param connection the MHD connection to handle - * @param response_code HTTP response code to use - * @param fmt format string for pack - * @param ... varargs - * @return MHD result code - */ -int -TAH_RESPONSE_reply_json_pack (struct MHD_Connection *connection, - unsigned int response_code, - const char *fmt, - ...) -{ - json_t *json; - va_list argp; - int ret; - json_error_t jerror; - - va_start (argp, fmt); - json = json_vpack_ex (&jerror, 0, fmt, argp); - va_end (argp); - if (NULL == json) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to pack JSON with format `%s': %s\n", - fmt, - jerror.text); - GNUNET_break (0); - return MHD_NO; - } - ret = TAH_RESPONSE_reply_json (connection, - json, - response_code); - json_decref (json); - return ret; -} - - -/** - * Send a response indicating an invalid argument. - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @param param_name the parameter that is invalid - * @return a MHD result code - */ -int -TAH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection, - enum TALER_ErrorCode ec, - const char *param_name) -{ - return TAH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:I, s:s}", - "error", "invalid parameter", - "code", (json_int_t) ec, - "parameter", param_name); -} - - -/** - * Send a response indicating an argument refering to a - * resource unknown to the auditor (i.e. unknown reserve or - * denomination key). - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @param param_name the parameter that is invalid - * @return a MHD result code - */ -int -TAH_RESPONSE_reply_arg_unknown (struct MHD_Connection *connection, - enum TALER_ErrorCode ec, - const char *param_name) -{ - return TAH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_NOT_FOUND, - "{s:s, s:I, s:s}", - "error", "unknown entity referenced", - "code", (json_int_t) ec, - "parameter", param_name); -} - - -/** - * Send a response indicating an invalid signature. - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @param param_name the parameter that is invalid - * @return a MHD result code - */ -int -TAH_RESPONSE_reply_signature_invalid (struct MHD_Connection *connection, - enum TALER_ErrorCode ec, - const char *param_name) -{ - return TAH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_UNAUTHORIZED, - "{s:s, s:I, s:s}", - "error", "invalid signature", - "code", (json_int_t) ec, - "parameter", param_name); -} - - -/** - * Send a response indicating a missing argument. - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @param param_name the parameter that is missing - * @return a MHD result code - */ -int -TAH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection, - enum TALER_ErrorCode ec, - const char *param_name) -{ - return TAH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:I, s:s}", - "error", "missing parameter", - "code", (json_int_t) ec, - "parameter", param_name); -} - - -/** - * Send a response indicating permission denied. - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @param hint hint about why access was denied - * @return a MHD result code - */ -int -TAH_RESPONSE_reply_permission_denied (struct MHD_Connection *connection, - enum TALER_ErrorCode ec, - const char *hint) -{ - return TAH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_FORBIDDEN, - "{s:s, s:I, s:s}", - "error", "permission denied", - "code", (json_int_t) ec, - "hint", hint); -} - - -/** - * Send a response indicating an internal error. - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @param hint hint about the internal error's nature - * @return a MHD result code - */ -int -TAH_RESPONSE_reply_internal_error (struct MHD_Connection *connection, - enum TALER_ErrorCode ec, - const char *hint) -{ - return TAH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - "{s:s, s:I, s:s}", - "error", "internal error", - "code", (json_int_t) ec, - "hint", hint); -} - - -/** - * Send a response indicating an external error. - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @param hint hint about the error's nature - * @return a MHD result code - */ -int -TAH_RESPONSE_reply_external_error (struct MHD_Connection *connection, - enum TALER_ErrorCode ec, - const char *hint) -{ - return TAH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:I, s:s}", - "error", "client error", - "code", (json_int_t) ec, - "hint", hint); -} - - -/** - * Send a response indicating an error committing a - * transaction (concurrent interference). - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @return a MHD result code - */ -int -TAH_RESPONSE_reply_commit_error (struct MHD_Connection *connection, - enum TALER_ErrorCode ec) -{ - return TAH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - "{s:s, s:I}", - "error", "commit failure", - "code", (json_int_t) ec); -} - - -/** - * Send a response indicating a failure to talk to the Auditor's - * database. - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @return a MHD result code - */ -int -TAH_RESPONSE_reply_internal_db_error (struct MHD_Connection *connection, - enum TALER_ErrorCode ec) -{ - return TAH_RESPONSE_reply_internal_error (connection, - ec, - "Failure in database interaction"); -} - - -/** - * Send a response indicating that the request was too big. - * - * @param connection the MHD connection to use - * @return a MHD result code - */ -int -TAH_RESPONSE_reply_request_too_large (struct MHD_Connection *connection) -{ - struct MHD_Response *resp; - int ret; - - resp = MHD_create_response_from_buffer (0, - NULL, - MHD_RESPMEM_PERSISTENT); - if (NULL == resp) - return MHD_NO; - TAH_RESPONSE_add_global_headers (resp); - ret = MHD_queue_response (connection, - MHD_HTTP_REQUEST_ENTITY_TOO_LARGE, - resp); - MHD_destroy_response (resp); - return ret; -} - - -/** - * Send a response indicating that the JSON was malformed. - * - * @param connection the MHD connection to use - * @return a MHD result code - */ -int -TAH_RESPONSE_reply_invalid_json (struct MHD_Connection *connection) -{ - return TAH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:I}", - "error", "invalid json", - "code", - (json_int_t) TALER_EC_JSON_INVALID); -} - - -/* end of taler-auditor-httpd_responses.c */ diff --git a/src/auditor/taler-auditor-httpd_responses.h b/src/auditor/taler-auditor-httpd_responses.h deleted file mode 100644 index 1cb5faa82..000000000 --- a/src/auditor/taler-auditor-httpd_responses.h +++ /dev/null @@ -1,245 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014 GNUnet e.V. - - 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 - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> -*/ - -/** - * @file taler-auditor-httpd_responses.h - * @brief API for generating generic replies of the auditor; these - * functions are called TAH_RESPONSE_reply_ and they generate - * and queue MHD response objects for a given connection. - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#ifndef TALER_AUDITOR_HTTPD_RESPONSES_H -#define TALER_AUDITOR_HTTPD_RESPONSES_H -#include <gnunet/gnunet_util_lib.h> -#include <jansson.h> -#include <microhttpd.h> -#include <pthread.h> -#include "taler_error_codes.h" -#include "taler-auditor-httpd.h" - - -/** - * Add headers we want to return in every response. - * Useful for testing, like if we want to always close - * connections. - * - * @param response response to modify - */ -void -TAH_RESPONSE_add_global_headers (struct MHD_Response *response); - - -/** - * Try to compress a response body. Updates @a buf and @a buf_size. - * - * @param[in,out] buf pointer to body to compress - * @param[in,out] buf_size pointer to initial size of @a buf - * @return #MHD_YES if @a buf was compressed - */ -int -TAH_RESPONSE_body_compress (void **buf, - size_t *buf_size); - - -/** - * Is HTTP body deflate compression supported by the client? - * - * @param connection connection to check - * @return #MHD_YES if 'deflate' compression is allowed - */ -int -TAH_RESPONSE_can_compress (struct MHD_Connection *connection); - - -/** - * Send JSON object as response. - * - * @param connection the MHD connection - * @param json the json object - * @param response_code the http response code - * @return MHD result code - */ -int -TAH_RESPONSE_reply_json (struct MHD_Connection *connection, - const json_t *json, - unsigned int response_code); - - -/** - * Function to call to handle the request by building a JSON - * reply from a format string and varargs. - * - * @param connection the MHD connection to handle - * @param response_code HTTP response code to use - * @param fmt format string for pack - * @param ... varargs - * @return MHD result code - */ -int -TAH_RESPONSE_reply_json_pack (struct MHD_Connection *connection, - unsigned int response_code, - const char *fmt, - ...); - - -/** - * Send a response indicating an invalid signature. - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @param param_name the parameter that is invalid - * @return a MHD result code - */ -int -TAH_RESPONSE_reply_signature_invalid (struct MHD_Connection *connection, - enum TALER_ErrorCode ec, - const char *param_name); - - -/** - * Send a response indicating an invalid argument. - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @param param_name the parameter that is invalid - * @return MHD result code - */ -int -TAH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection, - enum TALER_ErrorCode ec, - const char *param_name); - - -/** - * Send a response indicating an argument refering to a - * resource unknown to the auditor (i.e. unknown reserve or - * denomination key). - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @param param_name the parameter that is invalid - * @return a MHD result code - */ -int -TAH_RESPONSE_reply_arg_unknown (struct MHD_Connection *connection, - enum TALER_ErrorCode ec, - const char *param_name); - - -/** - * Send a response indicating a missing argument. - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @param param_name the parameter that is missing - * @return a MHD result code - */ -int -TAH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection, - enum TALER_ErrorCode ec, - const char *param_name); - - -/** - * Send a response indicating permission denied. - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @param hint hint about why access was denied - * @return a MHD result code - */ -int -TAH_RESPONSE_reply_permission_denied (struct MHD_Connection *connection, - enum TALER_ErrorCode ec, - const char *hint); - - -/** - * Send a response indicating an internal error. - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @param hint hint about the internal error's nature - * @return a MHD result code - */ -int -TAH_RESPONSE_reply_internal_error (struct MHD_Connection *connection, - enum TALER_ErrorCode ec, - const char *hint); - - -/** - * Send a response indicating an external error. - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @param hint hint about the error's nature - * @return a MHD result code - */ -int -TAH_RESPONSE_reply_external_error (struct MHD_Connection *connection, - enum TALER_ErrorCode ec, - const char *hint); - - -/** - * Send a response indicating an error committing a - * transaction (concurrent interference). - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @return a MHD result code - */ -int -TAH_RESPONSE_reply_commit_error (struct MHD_Connection *connection, - enum TALER_ErrorCode ec); - -/** - * Send a response indicating a failure to talk to the Auditor's - * database. - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @return a MHD result code - */ -int -TAH_RESPONSE_reply_internal_db_error (struct MHD_Connection *connection, - enum TALER_ErrorCode ec); - - -/** - * Send a response indicating that the request was too big. - * - * @param connection the MHD connection to use - * @return a MHD result code - */ -int -TAH_RESPONSE_reply_request_too_large (struct MHD_Connection *connection); - - -/** - * Send a response indicating that the JSON was malformed. - * - * @param connection the MHD connection to use - * @return a MHD result code - */ -int -TAH_RESPONSE_reply_invalid_json (struct MHD_Connection *connectionx); - - -#endif diff --git a/src/exchange-tools/Makefile.am b/src/exchange-tools/Makefile.am index 409c6bfdd..64b4cee87 100644 --- a/src/exchange-tools/Makefile.am +++ b/src/exchange-tools/Makefile.am @@ -16,6 +16,7 @@ bin_PROGRAMS = \ taler-exchange-keycheck \ taler-exchange-wire \ taler-exchange-dbinit \ + taler-exchange-tvg \ taler-wire taler_wire_SOURCES = \ @@ -59,6 +60,13 @@ taler_exchange_keycheck_LDADD = \ -lgnunetutil $(XLIB) taler_exchange_keycheck_LDFLAGS = $(POSTGRESQL_LDFLAGS) +taler_exchange_tvg_SOURCES = \ + taler-exchange-tvg.c +taler_exchange_tvg_LDADD = \ + $(LIBGCRYPT_LIBS) \ + $(top_builddir)/src/util/libtalerutil.la \ + -lgnunetutil $(XLIB) + taler_exchange_dbinit_SOURCES = \ taler-exchange-dbinit.c taler_exchange_dbinit_LDADD = \ diff --git a/src/exchange-tools/taler-exchange-tvg.c b/src/exchange-tools/taler-exchange-tvg.c new file mode 100644 index 000000000..55e658fc4 --- /dev/null +++ b/src/exchange-tools/taler-exchange-tvg.c @@ -0,0 +1,259 @@ +/* + This file is part of TALER + Copyright (C) 2019 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 + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ + +/** + * @file exchange-tools/taler-exchange-tvg.c + * @brief Generate test vectors for cryptographic operations. + * @author Florian Dold + */ +#include "platform.h" +#include "taler_util.h" +#include "taler_signatures.h" +#include <gnunet/gnunet_util_lib.h> + + +/** + * Print data base32-crockford with a preceding label. + * + * @param label label to print + * @param data data to print + * @param size size of data + */ +static void +display_data (char *label, void *data, size_t size) +{ + char *enc = GNUNET_STRINGS_data_to_string_alloc (data, size); + printf ("%s %s\n", label, enc); + GNUNET_free (enc); +} + + +/** + * Main function that will be run. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param cfg configuration + */ +static void +run (void *cls, + char *const *args, + const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + { + struct GNUNET_HashCode hc; + char *str = "Hello, GNU Taler"; + + GNUNET_CRYPTO_hash (str, strlen (str), &hc); + + printf ("hash code:\n"); + display_data (" input", str, strlen (str)); + display_data (" output", &hc, sizeof (struct GNUNET_HashCode)); + } + { + struct GNUNET_CRYPTO_EcdhePrivateKey *priv1; + struct GNUNET_CRYPTO_EcdhePublicKey pub1; + struct GNUNET_CRYPTO_EcdhePrivateKey *priv2; + struct GNUNET_HashCode skm; + priv1 = GNUNET_CRYPTO_ecdhe_key_create (); + priv2 = GNUNET_CRYPTO_ecdhe_key_create (); + GNUNET_CRYPTO_ecdhe_key_get_public (priv1, &pub1); + GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecc_ecdh (priv2, &pub1, &skm)); + + printf ("ecdhe key:\n"); + display_data (" priv1", priv1, sizeof (struct + GNUNET_CRYPTO_EcdhePrivateKey)); + display_data (" pub1", &pub1, sizeof (struct + GNUNET_CRYPTO_EcdhePublicKey)); + display_data (" priv2", priv2, sizeof (struct + GNUNET_CRYPTO_EcdhePrivateKey)); + display_data (" skm", &skm, sizeof (struct GNUNET_HashCode)); + GNUNET_free (priv1); + GNUNET_free (priv2); + } + + { + struct GNUNET_CRYPTO_EddsaPrivateKey *priv; + struct GNUNET_CRYPTO_EddsaPublicKey pub; + priv = GNUNET_CRYPTO_eddsa_key_create (); + GNUNET_CRYPTO_eddsa_key_get_public (priv, &pub); + + printf ("eddsa key:\n"); + display_data (" priv", priv, sizeof (struct + GNUNET_CRYPTO_EddsaPrivateKey)); + display_data (" pub", &pub, sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)); + GNUNET_free (priv); + } + { + struct GNUNET_CRYPTO_EddsaPrivateKey *priv; + struct GNUNET_CRYPTO_EddsaPublicKey pub; + struct GNUNET_CRYPTO_EddsaSignature sig; + struct TALER_ProposalDataPS data = { 0 }; + priv = GNUNET_CRYPTO_eddsa_key_create (); + GNUNET_CRYPTO_eddsa_key_get_public (priv, &pub); + data.purpose.size = htonl (sizeof (struct TALER_ProposalDataPS)); + GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (priv, &data.purpose, + &sig)); + GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_verify (0, + &data.purpose, + &sig, + &pub)); + + printf ("eddsa sig:\n"); + display_data (" priv", priv, sizeof (struct + GNUNET_CRYPTO_EddsaPrivateKey)); + display_data (" pub", &pub, sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)); + display_data (" data", &data, sizeof (struct TALER_ProposalDataPS)); + display_data (" sig", &sig, sizeof (struct GNUNET_CRYPTO_EddsaSignature)); + GNUNET_free (priv); + } + + { + size_t out_len = 64; + char out[out_len]; + char *ikm = "I'm the secret input key material"; + char *salt = "I'm very salty"; + char *ctx = "I'm a context chunk, also known as 'info' in the RFC"; + + GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_kdf (&out, + out_len, + salt, + strlen (salt), + ikm, + strlen (ikm), + ctx, + strlen (ctx), + NULL)); + + printf ("kdf:\n"); + display_data (" salt", salt, strlen (salt)); + display_data (" ikm", ikm, strlen (ikm)); + display_data (" ctx", ctx, strlen (ctx)); + printf (" out_len %u\n", (unsigned int) out_len); + display_data (" out", out, out_len); + } + { + struct GNUNET_CRYPTO_EcdhePrivateKey *priv_ecdhe; + struct GNUNET_CRYPTO_EcdhePublicKey pub_ecdhe; + struct GNUNET_CRYPTO_EddsaPrivateKey *priv_eddsa; + struct GNUNET_CRYPTO_EddsaPublicKey pub_eddsa; + struct GNUNET_HashCode key_material; + priv_ecdhe = GNUNET_CRYPTO_ecdhe_key_create (); + GNUNET_CRYPTO_ecdhe_key_get_public (priv_ecdhe, &pub_ecdhe); + priv_eddsa = GNUNET_CRYPTO_eddsa_key_create (); + GNUNET_CRYPTO_eddsa_key_get_public (priv_eddsa, &pub_eddsa); + GNUNET_CRYPTO_ecdh_eddsa (priv_ecdhe, &pub_eddsa, &key_material); + + printf ("eddsa_ecdh:\n"); + display_data (" priv_ecdhe", priv_ecdhe, sizeof (struct + GNUNET_CRYPTO_EcdhePrivateKey)); + display_data (" pub_ecdhe", &pub_ecdhe, sizeof (struct + GNUNET_CRYPTO_EcdhePublicKey)); + display_data (" priv_eddsa", priv_eddsa, sizeof (struct + GNUNET_CRYPTO_EddsaPrivateKey)); + display_data (" pub_eddsa", &pub_eddsa, sizeof (struct + GNUNET_CRYPTO_EddsaPublicKey)); + display_data (" key_material", &key_material, sizeof (struct + GNUNET_HashCode)); + } + + { + struct GNUNET_CRYPTO_RsaPrivateKey *skey; + struct GNUNET_CRYPTO_RsaPublicKey *pkey; + struct GNUNET_HashCode message_hash; + struct GNUNET_CRYPTO_RsaBlindingKeySecret bks; + struct GNUNET_CRYPTO_RsaSignature *blinded_sig; + struct GNUNET_CRYPTO_RsaSignature *sig; + char *blinded_data; + size_t blinded_len; + char *public_enc_data; + size_t public_enc_len; + char *blinded_sig_enc_data; + size_t blinded_sig_enc_length; + char *sig_enc_data; + size_t sig_enc_length; + skey = GNUNET_CRYPTO_rsa_private_key_create (2048); + pkey = GNUNET_CRYPTO_rsa_private_key_get_public (skey); + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, &message_hash, + sizeof (struct GNUNET_HashCode)); + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, &bks, sizeof (struct + GNUNET_CRYPTO_RsaBlindingKeySecret)); + GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_rsa_blind (&message_hash, &bks, + pkey, &blinded_data, + &blinded_len)); + blinded_sig = GNUNET_CRYPTO_rsa_sign_blinded (skey, blinded_data, + blinded_len); + sig = GNUNET_CRYPTO_rsa_unblind (blinded_sig, &bks, pkey); + GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_rsa_verify (&message_hash, sig, + pkey)); + public_enc_len = GNUNET_CRYPTO_rsa_public_key_encode (pkey, + &public_enc_data); + blinded_sig_enc_length = GNUNET_CRYPTO_rsa_signature_encode (blinded_sig, + & + blinded_sig_enc_data); + sig_enc_length = GNUNET_CRYPTO_rsa_signature_encode (sig, &sig_enc_data); + printf ("blind signing:\n"); + display_data (" message_hash", &message_hash, sizeof (struct + GNUNET_HashCode)); + display_data (" rsa_public_key", public_enc_data, public_enc_len); + display_data (" blinding_key_secret", &bks, sizeof (struct + GNUNET_CRYPTO_RsaBlindingKeySecret)); + display_data (" blinded_message", blinded_data, blinded_len); + display_data (" blinded_sig", blinded_sig_enc_data, + blinded_sig_enc_length); + display_data (" sig", sig_enc_data, sig_enc_length); + GNUNET_CRYPTO_rsa_private_key_free (skey); + GNUNET_CRYPTO_rsa_public_key_free (pkey); + GNUNET_CRYPTO_rsa_signature_free (sig); + GNUNET_CRYPTO_rsa_signature_free (blinded_sig); + } +} + + +/** + * The main function of the test vector generation tool. + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, + char *const *argv) +{ + const struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + /* force linker to link against libtalerutil; if we do + not do this, the linker may "optimize" libtalerutil + away and skip #TALER_OS_init(), which we do need */ + (void) TALER_project_data_default (); + GNUNET_assert (GNUNET_OK == + GNUNET_log_setup ("taler-exchange-dbinit", + "INFO", + NULL)); + if (GNUNET_OK != + GNUNET_PROGRAM_run (argc, argv, + "taler-exchange-tvg", + "Generate test vectors", + options, + &run, NULL)) + return 1; + return 0; +} diff --git a/src/exchange/Makefile.am b/src/exchange/Makefile.am index b5419a7a6..8e1621821 100644 --- a/src/exchange/Makefile.am +++ b/src/exchange/Makefile.am @@ -47,7 +47,6 @@ taler_exchange_httpd_SOURCES = \ taler-exchange-httpd_deposit.c taler-exchange-httpd_deposit.h \ taler-exchange-httpd_keystate.c taler-exchange-httpd_keystate.h \ taler-exchange-httpd_mhd.c taler-exchange-httpd_mhd.h \ - taler-exchange-httpd_parsing.c taler-exchange-httpd_parsing.h \ taler-exchange-httpd_payback.c taler-exchange-httpd_payback.h \ taler-exchange-httpd_refresh_link.c taler-exchange-httpd_refresh_link.h \ taler-exchange-httpd_refresh_melt.c taler-exchange-httpd_refresh_melt.h \ @@ -63,6 +62,7 @@ taler_exchange_httpd_SOURCES = \ taler_exchange_httpd_LDADD = \ $(LIBGCRYPT_LIBS) \ $(top_builddir)/src/wire/libtalerwire.la \ + $(top_builddir)/src/mhd/libtalermhd.la \ $(top_builddir)/src/json/libtalerjson.la \ $(top_builddir)/src/exchangedb/libtalerexchangedb.la \ $(top_builddir)/src/util/libtalerutil.la \ diff --git a/src/exchange/taler-exchange-aggregator.c b/src/exchange/taler-exchange-aggregator.c index 95f56d0df..98de86da0 100644 --- a/src/exchange/taler-exchange-aggregator.c +++ b/src/exchange/taler-exchange-aggregator.c @@ -1960,10 +1960,10 @@ main (int argc, options, &run, NULL)) { - GNUNET_free ((void*) argv); + GNUNET_free ((void *) argv); return 1; } - GNUNET_free ((void*) argv); + GNUNET_free ((void *) argv); return global_ret; } diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c index af38a605a..30efb8bc2 100644 --- a/src/exchange/taler-exchange-httpd.c +++ b/src/exchange/taler-exchange-httpd.c @@ -27,7 +27,7 @@ #include <microhttpd.h> #include <pthread.h> #include <sys/resource.h> -#include "taler-exchange-httpd_parsing.h" +#include "taler_mhd_lib.h" #include "taler-exchange-httpd_mhd.h" #include "taler-exchange-httpd_deposit.h" #include "taler-exchange-httpd_refund.h" @@ -174,7 +174,7 @@ handle_mhd_completion_callback (void *cls, "Request completed\n"); if (NULL == ecls) return; - TEH_PARSE_post_cleanup_callback (ecls->opaque_post_parsing_context); + TALER_MHD_parse_post_cleanup_callback (ecls->opaque_post_parsing_context); GNUNET_free (ecls); *con_cls = NULL; /* check that we didn't leave any transactions hanging */ @@ -487,122 +487,6 @@ handle_mhd_request (void *cls, /** - * Parse the configuration to determine on which port - * or UNIX domain path we should run an HTTP service. - * - * @param section section of the configuration to parse (usually "exchange") - * @param[out] rport set to the port number, or 0 for none - * @param[out] unix_path set to the UNIX path, or NULL for none - * @param[out] unix_mode set to the mode to be used for @a unix_path - * @return #GNUNET_OK on success - */ -static int -parse_port_config (const char *section, - uint16_t *rport, - char **unix_path, - mode_t *unix_mode) -{ - const char *choices[] = {"tcp", "unix"}; - const char *serve_type; - unsigned long long port; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_choice (cfg, - section, - "serve", - choices, - &serve_type)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - section, - "serve", - "serve type required"); - return GNUNET_SYSERR; - } - - if (0 == strcasecmp (serve_type, "tcp")) - { - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_number (cfg, - section, - "port", - &port)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - section, - "port", - "port number required"); - return GNUNET_SYSERR; - } - - if ( (0 == port) || - (port > UINT16_MAX) ) - { - fprintf (stderr, - "Invalid configuration (value out of range): %llu is not a valid port\n", - port); - return GNUNET_SYSERR; - } - *rport = (uint16_t) port; - *unix_path = NULL; - return GNUNET_OK; - } - if (0 == strcmp (serve_type, "unix")) - { - struct sockaddr_un s_un; - char *modestring; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_filename (cfg, - section, - "unixpath", - unix_path)) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - section, - "unixpath", - "unixpath required"); - return GNUNET_SYSERR; - } - if (strlen (*unix_path) >= sizeof (s_un.sun_path)) - { - fprintf (stderr, - "Invalid configuration: unix path too long\n"); - return GNUNET_SYSERR; - } - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (cfg, - section, - "UNIXPATH_MODE", - &modestring)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - section, - "UNIXPATH_MODE"); - return GNUNET_SYSERR; - } - errno = 0; - *unix_mode = (mode_t) strtoul (modestring, NULL, 8); - if (0 != errno) - { - GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - section, - "UNIXPATH_MODE", - "must be octal number"); - GNUNET_free (modestring); - return GNUNET_SYSERR; - } - GNUNET_free (modestring); - return GNUNET_OK; - } - /* not reached */ - GNUNET_assert (0); - return GNUNET_SYSERR; -} - - -/** * Load configuration parameters for the exchange * server into the corresponding global variables. * @@ -717,10 +601,11 @@ exchange_serve_process_config () } if (GNUNET_OK != - parse_port_config ("exchange", - &serve_port, - &serve_unixpath, - &unixpath_mode)) + TALER_MHD_parse_config (cfg, + "exchange", + &serve_port, + &serve_unixpath, + &unixpath_mode)) { TEH_VALIDATION_done (); return GNUNET_SYSERR; @@ -843,141 +728,6 @@ connection_done (void *cls, /* end of HAVE_DEVELOPER */ #endif -/** - * Function called for logging by MHD. - * - * @param cls closure, NULL - * @param fm format string (`printf()`-style) - * @param ap arguments to @a fm - */ -static void -handle_mhd_logs (void *cls, - const char *fm, - va_list ap) -{ - static int cache; - char buf[2048]; - - (void) cls; - if (-1 == cache) - return; - if (0 == cache) - { - if (0 == - GNUNET_get_log_call_status (GNUNET_ERROR_TYPE_INFO, - "libmicrohttpd", - __FILE__, - __FUNCTION__, - __LINE__)) - { - cache = -1; - return; - } - } - cache = 1; - vsnprintf (buf, - sizeof (buf), - fm, - ap); - GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_INFO, - "libmicrohttpd", - "%s", - buf); -} - - -/** - * Open UNIX domain socket for listining at @a unix_path with - * permissions @a unix_mode. - * - * @param unix_path where to listen - * @param unix_mode access permissions to set - * @return -1 on error, otherwise the listen socket - */ -static int -open_unix_path (const char *unix_path, - mode_t unix_mode) -{ - struct GNUNET_NETWORK_Handle *nh; - struct sockaddr_un *un; - int fd; - - if (sizeof (un->sun_path) <= strlen (unix_path)) - { - fprintf (stderr, - "unixpath `%s' too long\n", - unix_path); - return -1; - } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Creating listen socket '%s' with mode %o\n", - unix_path, - unix_mode); - - if (GNUNET_OK != - GNUNET_DISK_directory_create_for_file (unix_path)) - { - GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, - "mkdir", - unix_path); - } - - un = GNUNET_new (struct sockaddr_un); - un->sun_family = AF_UNIX; - strncpy (un->sun_path, - unix_path, - sizeof (un->sun_path) - 1); - GNUNET_NETWORK_unix_precheck (un); - - if (NULL == (nh = GNUNET_NETWORK_socket_create (AF_UNIX, - SOCK_STREAM, - 0))) - { - fprintf (stderr, - "create failed for AF_UNIX\n"); - GNUNET_free (un); - return -1; - } - if (GNUNET_OK != - GNUNET_NETWORK_socket_bind (nh, - (void *) un, - sizeof (struct sockaddr_un))) - { - fprintf (stderr, - "bind failed for AF_UNIX\n"); - GNUNET_free (un); - GNUNET_NETWORK_socket_close (nh); - return -1; - } - GNUNET_free (un); - if (GNUNET_OK != - GNUNET_NETWORK_socket_listen (nh, - UNIX_BACKLOG)) - { - fprintf (stderr, - "listen failed for AF_UNIX\n"); - GNUNET_NETWORK_socket_close (nh); - return -1; - } - - if (0 != chmod (unix_path, - unix_mode)) - { - fprintf (stderr, - "chmod failed: %s\n", - strerror (errno)); - GNUNET_NETWORK_socket_close (nh); - return -1; - } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "set socket '%s' to mode %o\n", - unix_path, - unix_mode); - fd = GNUNET_NETWORK_get_fd (nh); - GNUNET_NETWORK_socket_free_memory_only_ (nh); - return fd; -} - /** * Called when the main thread exits, writes out performance @@ -986,7 +736,6 @@ open_unix_path (const char *unix_path, static void write_stats () { - struct GNUNET_DISK_FileHandle *fh; pid_t pid = getpid (); char *benchmark_dir; @@ -1074,12 +823,17 @@ main (int argc, const char *listen_pid; const char *listen_fds; int fh = -1; + enum TALER_MHD_GlobalOptions go; if (0 >= GNUNET_GETOPT_run ("taler-exchange-httpd", options, argc, argv)) return 1; + go = TALER_MHD_GO_NONE; + if (TEH_exchange_connection_close) + go |= TALER_MHD_GO_FORCE_CONNECTION_CLOSE; + TALER_MHD_setup (go); GNUNET_assert (GNUNET_OK == GNUNET_log_setup ("taler-exchange-httpd", (NULL == loglev) ? "INFO" : loglev, @@ -1138,8 +892,8 @@ main (int argc, if ( (-1 == fh) && (NULL != serve_unixpath) ) { - fh = open_unix_path (serve_unixpath, - unixpath_mode); + fh = TALER_MHD_open_unix_path (serve_unixpath, + unixpath_mode); if (-1 == fh) return 1; } @@ -1155,7 +909,8 @@ main (int argc, MHD_OPTION_THREAD_POOL_SIZE, (unsigned int) 32, MHD_OPTION_LISTEN_BACKLOG_SIZE, (unsigned int) 1024, MHD_OPTION_LISTEN_SOCKET, fh, - MHD_OPTION_EXTERNAL_LOGGER, &handle_mhd_logs, NULL, + MHD_OPTION_EXTERNAL_LOGGER, &TALER_MHD_handle_logs, + NULL, MHD_OPTION_NOTIFY_COMPLETED, &handle_mhd_completion_callback, NULL, MHD_OPTION_CONNECTION_TIMEOUT, connection_timeout, diff --git a/src/exchange/taler-exchange-httpd_db.c b/src/exchange/taler-exchange-httpd_db.c index 37bd23792..19781f97f 100644 --- a/src/exchange/taler-exchange-httpd_db.c +++ b/src/exchange/taler-exchange-httpd_db.c @@ -23,6 +23,7 @@ #include <jansson.h> #include <gnunet/gnunet_json_lib.h> #include "taler_json_lib.h" +#include "taler_mhd_lib.h" #include "taler-exchange-httpd_responses.h" #include "taler-exchange-httpd_keystate.h" @@ -62,8 +63,10 @@ TEH_DB_know_coin_transaction (void *cls, if (GNUNET_DB_STATUS_HARD_ERROR == qs) { *mhd_ret - = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_DB_COIN_HISTORY_STORE_ERROR); + = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_DB_COIN_HISTORY_STORE_ERROR, + "could not persist coin data"); return GNUNET_DB_STATUS_HARD_ERROR; } return qs; @@ -99,8 +102,10 @@ TEH_DB_run_transaction (struct MHD_Connection *connection, { GNUNET_break (0); if (NULL != mhd_ret) - *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_DB_SETUP_FAILED); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_DB_SETUP_FAILED, + "could not establish database session"); return GNUNET_SYSERR; } TEH_plugin->preflight (TEH_plugin->cls, @@ -117,8 +122,10 @@ TEH_DB_run_transaction (struct MHD_Connection *connection, { GNUNET_break (0); if (NULL != mhd_ret) - *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_DB_START_FAILED); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_DB_START_FAILED, + "could not begin transaction"); return GNUNET_SYSERR; } qs = cb (cb_cls, @@ -136,8 +143,10 @@ TEH_DB_run_transaction (struct MHD_Connection *connection, if (GNUNET_DB_STATUS_HARD_ERROR == qs) { if (NULL != mhd_ret) - *mhd_ret = TEH_RESPONSE_reply_commit_error (connection, - TALER_EC_DB_COMMIT_FAILED_HARD); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_DB_COMMIT_FAILED_HARD, + "could not commit database transaction"); return GNUNET_SYSERR; } /* make sure callback did not violate invariants! */ @@ -150,8 +159,10 @@ TEH_DB_run_transaction (struct MHD_Connection *connection, name, MAX_TRANSACTION_COMMIT_RETRIES); if (NULL != mhd_ret) - *mhd_ret = TEH_RESPONSE_reply_commit_error (connection, - TALER_EC_DB_COMMIT_FAILED_ON_RETRY); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_DB_COMMIT_FAILED_ON_RETRY, + "repatedly failed to serialize database transaction"); return GNUNET_SYSERR; } diff --git a/src/exchange/taler-exchange-httpd_deposit.c b/src/exchange/taler-exchange-httpd_deposit.c index fd36bb4a0..23a97fb1b 100644 --- a/src/exchange/taler-exchange-httpd_deposit.c +++ b/src/exchange/taler-exchange-httpd_deposit.c @@ -29,7 +29,7 @@ #include <microhttpd.h> #include <pthread.h> #include "taler_json_lib.h" -#include "taler-exchange-httpd_parsing.h" +#include "taler_mhd_lib.h" #include "taler-exchange-httpd_deposit.h" #include "taler-exchange-httpd_responses.h" #include "taler-exchange-httpd_keystate.h" @@ -83,17 +83,17 @@ reply_deposit_success (struct MHD_Connection *connection, &pub, &sig)) { - return TEH_RESPONSE_reply_internal_error (connection, - TALER_EC_EXCHANGE_BAD_CONFIGURATION, - "no keys"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_EXCHANGE_BAD_CONFIGURATION, + "no keys"); } - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:s, s:o, s:o}", - "status", "DEPOSIT_OK", - "sig", GNUNET_JSON_from_data_auto (&sig), - "pub", GNUNET_JSON_from_data_auto ( - &pub)); + return TALER_MHD_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:s, s:o, s:o}", + "status", "DEPOSIT_OK", + "sig", GNUNET_JSON_from_data_auto (&sig), + "pub", GNUNET_JSON_from_data_auto (&pub)); } @@ -149,8 +149,10 @@ deposit_transaction (void *cls, { if (GNUNET_DB_STATUS_HARD_ERROR == qs) { - *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_DEPOSIT_HISTORY_DB_ERROR); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_DEPOSIT_HISTORY_DB_ERROR, + "Could not check for existing identical deposit"); return GNUNET_DB_STATUS_HARD_ERROR; } return qs; @@ -197,8 +199,10 @@ deposit_transaction (void *cls, { TEH_plugin->free_coin_transaction_list (TEH_plugin->cls, tl); - *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_DEPOSIT_HISTORY_DB_ERROR); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_DEPOSIT_HISTORY_DB_ERROR, + "could not access coin history"); return GNUNET_DB_STATUS_HARD_ERROR; } /* Check that cost of all transactions is smaller than @@ -223,8 +227,10 @@ deposit_transaction (void *cls, if (GNUNET_DB_STATUS_HARD_ERROR == qs) { TALER_LOG_WARNING ("Failed to store /deposit information in database\n"); - *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_DEPOSIT_STORE_DB_ERROR); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_DEPOSIT_STORE_DB_ERROR, + "Could not persist /deposit data"); } return qs; } @@ -273,9 +279,10 @@ verify_and_execute_deposit (struct MHD_Connection *connection, &deposit->coin.coin_pub.eddsa_pub)) { TALER_LOG_WARNING ("Invalid signature on /deposit request\n"); - return TEH_RESPONSE_reply_signature_invalid (connection, - TALER_EC_DEPOSIT_COIN_SIGNATURE_INVALID, - "coin_sig"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_UNAUTHORIZED, + TALER_EC_DEPOSIT_COIN_SIGNATURE_INVALID, + "coin_sig"); } /* check denomination */ @@ -283,9 +290,10 @@ verify_and_execute_deposit (struct MHD_Connection *connection, if (NULL == mks) { TALER_LOG_ERROR ("Lacking keys to operate\n"); - return TEH_RESPONSE_reply_internal_error (connection, - TALER_EC_EXCHANGE_BAD_CONFIGURATION, - "no keys"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_EXCHANGE_BAD_CONFIGURATION, + "no keys"); } dki = TEH_KS_denomination_key_lookup_by_hash (mks, &deposit->coin.denom_pub_hash, @@ -295,9 +303,10 @@ verify_and_execute_deposit (struct MHD_Connection *connection, if (NULL == dki) { TEH_KS_release (mks); - return TEH_RESPONSE_reply_with_error (connection, - ec, - hc); + return TALER_MHD_reply_with_error (connection, + hc, + ec, + "Could not find denomination key used in deposit"); } TALER_amount_ntoh (&dc.value, &dki->issue.properties.value); @@ -418,11 +427,11 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh, }; (void) rh; - res = TEH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &json); + res = TALER_MHD_parse_post_json (connection, + connection_cls, + upload_data, + upload_data_size, + &json); if (GNUNET_SYSERR == res) return MHD_NO; if ( (GNUNET_NO == res) || @@ -431,9 +440,9 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh, memset (&deposit, 0, sizeof (deposit)); - res = TEH_PARSE_json_data (connection, - json, - spec); + res = TALER_MHD_parse_json_data (connection, + json, + spec); json_decref (json); if (GNUNET_SYSERR == res) return MHD_NO; /* hard failure */ @@ -445,9 +454,10 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh, { GNUNET_break_op (0); GNUNET_JSON_parse_free (spec); - return TEH_RESPONSE_reply_arg_invalid (connection, - TALER_EC_DEPOSIT_REFUND_DEADLINE_AFTER_WIRE_DEADLINE, - "refund_deadline"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_DEPOSIT_REFUND_DEADLINE_AFTER_WIRE_DEADLINE, + "refund_deadline"); } if (TALER_EC_NONE != @@ -455,9 +465,10 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh, &emsg))) { GNUNET_JSON_parse_free (spec); - res = TEH_RESPONSE_reply_external_error (connection, - ec, - emsg); + res = TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + ec, + emsg); GNUNET_free (emsg); return res; } @@ -466,9 +477,10 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh, { GNUNET_break_op (0); GNUNET_JSON_parse_free (spec); - return TEH_RESPONSE_reply_arg_invalid (connection, - TALER_EC_DEPOSIT_INVALID_TIMESTAMP, - "timestamp"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_DEPOSIT_INVALID_TIMESTAMP, + "timestamp"); } if (GNUNET_OK != TALER_JSON_merchant_wire_signature_hash (wire, @@ -477,18 +489,20 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh, TALER_LOG_WARNING ( "Failed to parse JSON wire format specification for /deposit request\n"); GNUNET_JSON_parse_free (spec); - return TEH_RESPONSE_reply_arg_invalid (connection, - TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_JSON, - "wire"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_JSON, + "wire"); } if (0 != GNUNET_memcmp (&deposit.h_wire, &my_h_wire)) { /* Client hashed contract differently than we did, reject */ GNUNET_JSON_parse_free (spec); - return TEH_RESPONSE_reply_arg_invalid (connection, - TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_CONTRACT_HASH_CONFLICT, - "H_wire"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_CONTRACT_HASH_CONFLICT, + "H_wire"); } /* check denomination exists and is valid */ @@ -497,9 +511,10 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh, { TALER_LOG_ERROR ("Lacking keys to operate\n"); GNUNET_JSON_parse_free (spec); - return TEH_RESPONSE_reply_internal_error (connection, - TALER_EC_EXCHANGE_BAD_CONFIGURATION, - "no keys"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_EXCHANGE_BAD_CONFIGURATION, + "no keys"); } dki = TEH_KS_denomination_key_lookup_by_hash (key_state, &deposit.coin.denom_pub_hash, @@ -511,9 +526,10 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh, TEH_KS_release (key_state); TALER_LOG_WARNING ("Unknown denomination key in /deposit request\n"); GNUNET_JSON_parse_free (spec); - return TEH_RESPONSE_reply_with_error (connection, - ec, - hc); + return TALER_MHD_reply_with_error (connection, + hc, + ec, + "Could not find denomination key used in deposit"); } TALER_amount_ntoh (&deposit.deposit_fee, &dki->issue.properties.fee_deposit); @@ -525,9 +541,10 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh, TALER_LOG_WARNING ("Invalid coin passed for /deposit\n"); TEH_KS_release (key_state); GNUNET_JSON_parse_free (spec); - return TEH_RESPONSE_reply_signature_invalid (connection, - TALER_EC_DEPOSIT_DENOMINATION_SIGNATURE_INVALID, - "ub_sig"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_UNAUTHORIZED, + TALER_EC_DEPOSIT_DENOMINATION_SIGNATURE_INVALID, + "ub_sig"); } TALER_amount_ntoh (&deposit.deposit_fee, &dki->issue.properties.fee_deposit); @@ -538,9 +555,10 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh, { GNUNET_break_op (0); GNUNET_JSON_parse_free (spec); - return TEH_RESPONSE_reply_external_error (connection, - TALER_EC_DEPOSIT_NEGATIVE_VALUE_AFTER_FEE, - "deposited amount smaller than depositing fee"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_DEPOSIT_NEGATIVE_VALUE_AFTER_FEE, + "deposited amount smaller than depositing fee"); } /* make sure coin is 'known' in database */ diff --git a/src/exchange/taler-exchange-httpd_keystate.c b/src/exchange/taler-exchange-httpd_keystate.c index bde5c7d7e..cf5cbe9a0 100644 --- a/src/exchange/taler-exchange-httpd_keystate.c +++ b/src/exchange/taler-exchange-httpd_keystate.c @@ -23,6 +23,7 @@ #include "platform.h" #include <pthread.h> #include "taler_json_lib.h" +#include "taler_mhd_lib.h" #include "taler-exchange-httpd_keystate.h" #include "taler-exchange-httpd_responses.h" #include "taler_exchangedb_plugin.h" @@ -1242,7 +1243,7 @@ setup_general_response_headers (const struct TEH_KS_StateHandle *key_state, { char dat[128]; - TEH_RESPONSE_add_global_headers (response); + TALER_MHD_add_global_headers (response); GNUNET_break (MHD_YES == MHD_add_response_header (response, MHD_HTTP_HEADER_CONTENT_TYPE, @@ -1545,8 +1546,8 @@ build_keys_response (const struct ResponseFactoryContext *rfc, } /* Also compute compressed version of /keys response */ - comp = TEH_RESPONSE_body_compress (&keys_jsonz, - &keys_jsonz_size); + comp = TALER_MHD_body_compress (&keys_jsonz, + &keys_jsonz_size); krd->response_compressed = MHD_create_response_from_buffer (keys_jsonz_size, keys_jsonz, @@ -2378,9 +2379,10 @@ TEH_KS_handler_keys (struct TEH_RequestHandler *rh, &cherrypickn)) { GNUNET_break_op (0); - return TEH_RESPONSE_reply_arg_invalid (connection, - TALER_EC_KEYS_HAVE_NOT_NUMERIC, - "last_issue_date"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_KEYS_HAVE_NOT_NUMERIC, + "last_issue_date"); } last_issue_date.abs_value_us = (uint64_t) cherrypickn * 1000000LLU; } @@ -2402,9 +2404,10 @@ TEH_KS_handler_keys (struct TEH_RequestHandler *rh, &fakenown)) { GNUNET_break_op (0); - return TEH_RESPONSE_reply_arg_invalid (connection, - TALER_EC_KEYS_HAVE_NOT_NUMERIC, - "now"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_KEYS_HAVE_NOT_NUMERIC, + "now"); } now.abs_value_us = (uint64_t) fakenown * 1000000LLU; } @@ -2413,9 +2416,10 @@ TEH_KS_handler_keys (struct TEH_RequestHandler *rh, if (NULL == key_state) { TALER_LOG_ERROR ("Lacking keys to operate\n"); - return TEH_RESPONSE_reply_internal_error (connection, - TALER_EC_EXCHANGE_BAD_CONFIGURATION, - "no keys"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_EXCHANGE_BAD_CONFIGURATION, + "no keys"); } krd = bsearch (&last_issue_date, key_state->krd_array, @@ -2444,7 +2448,7 @@ TEH_KS_handler_keys (struct TEH_RequestHandler *rh, } ret = MHD_queue_response (connection, rh->response_code, - (MHD_YES == TEH_RESPONSE_can_compress (connection)) + (MHD_YES == TALER_MHD_can_compress (connection)) ? krd->response_compressed : krd->response_uncompressed); TEH_KS_release (key_state); diff --git a/src/exchange/taler-exchange-httpd_keystate.h b/src/exchange/taler-exchange-httpd_keystate.h index 708b043b5..5d92af2b2 100644 --- a/src/exchange/taler-exchange-httpd_keystate.h +++ b/src/exchange/taler-exchange-httpd_keystate.h @@ -26,6 +26,7 @@ #include <gnunet/gnunet_util_lib.h> #include <microhttpd.h> #include "taler-exchange-httpd.h" +#include "taler_error_codes.h" #include "taler_exchangedb_lib.h" diff --git a/src/exchange/taler-exchange-httpd_mhd.c b/src/exchange/taler-exchange-httpd_mhd.c index 95e51c8ed..825a1b310 100644 --- a/src/exchange/taler-exchange-httpd_mhd.c +++ b/src/exchange/taler-exchange-httpd_mhd.c @@ -28,6 +28,7 @@ #include <jansson.h> #include <microhttpd.h> #include <pthread.h> +#include "taler_mhd_lib.h" #include "taler-exchange-httpd_responses.h" #include "taler-exchange-httpd.h" #include "taler-exchange-httpd_mhd.h" @@ -66,7 +67,7 @@ TEH_MHD_handler_static_response (struct TEH_RequestHandler *rh, GNUNET_break (0); return MHD_NO; } - TEH_RESPONSE_add_global_headers (response); + TALER_MHD_add_global_headers (response); if (NULL != rh->mime_type) (void) MHD_add_response_header (response, MHD_HTTP_HEADER_CONTENT_TYPE, @@ -97,41 +98,12 @@ TEH_MHD_handler_agpl_redirect (struct TEH_RequestHandler *rh, const char *upload_data, size_t *upload_data_size) { - const char *agpl = - "This server is licensed under the Affero GPL. You will now be redirected to the source code."; - struct MHD_Response *response; - int ret; - + (void) rh; (void) connection_cls; (void) upload_data; (void) upload_data_size; - response = MHD_create_response_from_buffer (strlen (agpl), - (void *) agpl, - MHD_RESPMEM_PERSISTENT); - if (NULL == response) - { - GNUNET_break (0); - return MHD_NO; - } - TEH_RESPONSE_add_global_headers (response); - if (NULL != rh->mime_type) - (void) MHD_add_response_header (response, - MHD_HTTP_HEADER_CONTENT_TYPE, - rh->mime_type); - if (MHD_NO == - MHD_add_response_header (response, - MHD_HTTP_HEADER_LOCATION, - "http://www.git.taler.net/?p=exchange.git")) - { - GNUNET_break (0); - MHD_destroy_response (response); - return MHD_NO; - } - ret = MHD_queue_response (connection, - rh->response_code, - response); - MHD_destroy_response (response); - return ret; + return TALER_MHD_reply_agpl (connection, + "http://www.git.taler.net/?p=exchange.git"); } @@ -156,11 +128,11 @@ TEH_MHD_handler_send_json_pack_error (struct TEH_RequestHandler *rh, (void) connection_cls; (void) upload_data; (void) upload_data_size; - return TEH_RESPONSE_reply_json_pack (connection, - rh->response_code, - "{s:s}", - "error", - rh->data); + return TALER_MHD_reply_json_pack (connection, + rh->response_code, + "{s:s}", + "error", + rh->data); } diff --git a/src/exchange/taler-exchange-httpd_parsing.h b/src/exchange/taler-exchange-httpd_parsing.h deleted file mode 100644 index 9c5381756..000000000 --- a/src/exchange/taler-exchange-httpd_parsing.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014, 2015, 2016 GNUnet e.V. - - 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 - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-exchange-httpd_parsing.h - * @brief functions to parse incoming requests - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#ifndef TALER_EXCHANGE_HTTPD_PARSING_H -#define TALER_EXCHANGE_HTTPD_PARSING_H - -#include <microhttpd.h> -#include <jansson.h> -#include "taler_util.h" -#include "taler_json_lib.h" - - -/** - * Process a POST request containing a JSON object. This - * function realizes an MHD POST processor that will - * (incrementally) process JSON data uploaded to the HTTP - * server. It will store the required state in the - * "connection_cls", which must be cleaned up using - * #TEH_PARSE_post_cleanup_callback(). - * - * @param connection the MHD connection - * @param con_cls the closure (points to a `struct Buffer *`) - * @param upload_data the POST data - * @param upload_data_size number of bytes in @a upload_data - * @param json the JSON object for a completed request - * @return - * #GNUNET_YES if json object was parsed or at least - * may be parsed in the future (call again); - * `*json` will be NULL if we need to be called again, - * and non-NULL if we are done. - * #GNUNET_NO is request incomplete or invalid - * (error message was generated) - * #GNUNET_SYSERR on internal error - * (we could not even queue an error message, - * close HTTP session with MHD_NO) - */ -int -TEH_PARSE_post_json (struct MHD_Connection *connection, - void **con_cls, - const char *upload_data, - size_t *upload_data_size, - json_t **json); - - -/** - * Function called whenever we are done with a request - * to clean up our state. - * - * @param con_cls value as it was left by - * #TEH_PARSE_post_json(), to be cleaned up - */ -void -TEH_PARSE_post_cleanup_callback (void *con_cls); - - -/** - * Parse JSON object into components based on the given field - * specification. - * - * @param connection the connection to send an error response to - * @param root the JSON node to start the navigation at. - * @param spec field specification for the parser - * @return - * #GNUNET_YES if navigation was successful (caller is responsible - * for freeing allocated variable-size data using - * GNUNET_JSON_parse_free() when done) - * #GNUNET_NO if json is malformed, error response was generated - * #GNUNET_SYSERR on internal error - */ -int -TEH_PARSE_json_data (struct MHD_Connection *connection, - const json_t *root, - struct GNUNET_JSON_Specification *spec); - - -/** - * Parse JSON array into components based on the given field - * specification. Generates error response on parse errors. - * - * @param connection the connection to send an error response to - * @param root the JSON node to start the navigation at. - * @param[in,out] spec field specification for the parser - * @param ... -1-terminated list of array offsets of type 'int' - * @return - * #GNUNET_YES if navigation was successful (caller is responsible - * for freeing allocated variable-size data using - * GNUNET_JSON_parse_free() when done) - * #GNUNET_NO if json is malformed, error response was generated - * #GNUNET_SYSERR on internal error - */ -int -TEH_PARSE_json_array (struct MHD_Connection *connection, - const json_t *root, - struct GNUNET_JSON_Specification *spec, - ...); - - -/** - * Extraxt fixed-size base32crockford encoded data from request. - * - * Queues an error response to the connection if the parameter is missing or - * invalid. - * - * @param connection the MHD connection - * @param param_name the name of the parameter with the key - * @param[out] out_data pointer to store the result - * @param out_size expected size of @a out_data - * @return - * #GNUNET_YES if the the argument is present - * #GNUNET_NO if the argument is absent or malformed - * #GNUNET_SYSERR on internal error (error response could not be sent) - */ -int -TEH_PARSE_mhd_request_arg_data (struct MHD_Connection *connection, - const char *param_name, - void *out_data, - size_t out_size); - - -#endif /* TALER_EXCHANGE_HTTPD_PARSING_H */ diff --git a/src/exchange/taler-exchange-httpd_payback.c b/src/exchange/taler-exchange-httpd_payback.c index 05a2355a3..b7fe593d9 100644 --- a/src/exchange/taler-exchange-httpd_payback.c +++ b/src/exchange/taler-exchange-httpd_payback.c @@ -27,7 +27,7 @@ #include <microhttpd.h> #include <pthread.h> #include "taler_json_lib.h" -#include "taler-exchange-httpd_parsing.h" +#include "taler_mhd_lib.h" #include "taler-exchange-httpd_payback.h" #include "taler-exchange-httpd_responses.h" #include "taler-exchange-httpd_keystate.h" @@ -35,26 +35,6 @@ /** - * A wallet asked for /payback, but we do not know anything about the - * original withdraw operation specified. Generates a 404 reply. - * - * @param connection connection to the client - * @param ec Taler error code - * @return MHD result code - */ -static int -reply_payback_unknown (struct MHD_Connection *connection, - enum TALER_ErrorCode ec) -{ - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_NOT_FOUND, - "{s:s, s:I}", - "error", "blinded coin unknown", - "code", (json_int_t) ec); -} - - -/** * A wallet asked for /payback, return the successful response. * * @param connection connection to the client @@ -88,24 +68,25 @@ reply_payback_refresh_success (struct MHD_Connection *connection, &pub, &sig)) { - return TEH_RESPONSE_reply_internal_error (connection, - TALER_EC_EXCHANGE_BAD_CONFIGURATION, - "no keys"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_EXCHANGE_BAD_CONFIGURATION, + "no keys"); } - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:o, s:o, s:o, s:o, s:o}", - "old_coin_pub", - GNUNET_JSON_from_data_auto ( - old_coin_pub), - "timestamp", GNUNET_JSON_from_time_abs ( - timestamp), - "amount", TALER_JSON_from_amount ( - amount), - "exchange_sig", - GNUNET_JSON_from_data_auto (&sig), - "exchange_pub", - GNUNET_JSON_from_data_auto (&pub)); + return TALER_MHD_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:o, s:o, s:o, s:o, s:o}", + "old_coin_pub", + GNUNET_JSON_from_data_auto ( + old_coin_pub), + "timestamp", GNUNET_JSON_from_time_abs ( + timestamp), + "amount", TALER_JSON_from_amount ( + amount), + "exchange_sig", + GNUNET_JSON_from_data_auto (&sig), + "exchange_pub", + GNUNET_JSON_from_data_auto (&pub)); } @@ -142,23 +123,24 @@ reply_payback_success (struct MHD_Connection *connection, &pub, &sig)) { - return TEH_RESPONSE_reply_internal_error (connection, - TALER_EC_EXCHANGE_BAD_CONFIGURATION, - "no keys"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_EXCHANGE_BAD_CONFIGURATION, + "no keys"); } - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:o, s:o, s:o, s:o, s:o}", - "reserve_pub", - GNUNET_JSON_from_data_auto (reserve_pub), - "timestamp", GNUNET_JSON_from_time_abs ( - timestamp), - "amount", TALER_JSON_from_amount ( - amount), - "exchange_sig", - GNUNET_JSON_from_data_auto (&sig), - "exchange_pub", - GNUNET_JSON_from_data_auto (&pub)); + return TALER_MHD_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:o, s:o, s:o, s:o, s:o}", + "reserve_pub", + GNUNET_JSON_from_data_auto (reserve_pub), + "timestamp", GNUNET_JSON_from_time_abs ( + timestamp), + "amount", TALER_JSON_from_amount ( + amount), + "exchange_sig", + GNUNET_JSON_from_data_auto (&sig), + "exchange_pub", + GNUNET_JSON_from_data_auto (&pub)); } @@ -268,8 +250,10 @@ payback_transaction (void *cls, if (GNUNET_DB_STATUS_HARD_ERROR == qs) { GNUNET_break (0); - *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_PAYBACK_DB_FETCH_FAILED); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_PAYBACK_DB_FETCH_FAILED, + "failed to fetch old coin of blind coin"); } return qs; } @@ -285,8 +269,10 @@ payback_transaction (void *cls, if (GNUNET_DB_STATUS_HARD_ERROR == qs) { GNUNET_break (0); - *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_PAYBACK_DB_FETCH_FAILED); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_PAYBACK_DB_FETCH_FAILED, + "failed to fetch reserve of blinded coin"); } return qs; } @@ -296,8 +282,10 @@ payback_transaction (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Payback requested for unknown envelope %s\n", GNUNET_h2s (&pc->h_blind)); - *mhd_ret = reply_payback_unknown (connection, - TALER_EC_PAYBACK_WITHDRAW_NOT_FOUND); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_PAYBACK_WITHDRAW_NOT_FOUND, + "blind coin unknown"); return GNUNET_DB_STATUS_HARD_ERROR; } @@ -312,8 +300,10 @@ payback_transaction (void *cls, if (GNUNET_DB_STATUS_HARD_ERROR == qs) { GNUNET_break (0); - *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_PAYBACK_DB_FETCH_FAILED); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_PAYBACK_DB_FETCH_FAILED, + "failed to fetch old coin transaction history"); } return qs; } @@ -329,8 +319,10 @@ payback_transaction (void *cls, GNUNET_break (0); TEH_plugin->free_coin_transaction_list (TEH_plugin->cls, tl); - *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_PAYBACK_HISTORY_DB_ERROR); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_PAYBACK_HISTORY_DB_ERROR, + "failed to calculate old coin transaction history"); return GNUNET_DB_STATUS_HARD_ERROR; } if (GNUNET_SYSERR == @@ -341,8 +333,10 @@ payback_transaction (void *cls, GNUNET_break (0); TEH_plugin->free_coin_transaction_list (TEH_plugin->cls, tl); - *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_PAYBACK_COIN_BALANCE_NEGATIVE); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_PAYBACK_COIN_BALANCE_NEGATIVE, + "calculated negative old coin balance"); return GNUNET_DB_STATUS_HARD_ERROR; } if ( (0 == pc->amount.fraction) && @@ -391,8 +385,10 @@ payback_transaction (void *cls, if (GNUNET_DB_STATUS_HARD_ERROR == qs) { TALER_LOG_WARNING ("Failed to store /payback information in database\n"); - *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_PAYBACK_DB_PUT_FAILED); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_PAYBACK_DB_PUT_FAILED, + "failed to persist payback data"); } return qs; } @@ -437,9 +433,10 @@ verify_and_execute_payback (struct MHD_Connection *connection, if (NULL == key_state) { TALER_LOG_ERROR ("Lacking keys to operate\n"); - return TEH_RESPONSE_reply_internal_error (connection, - TALER_EC_EXCHANGE_BAD_CONFIGURATION, - "no keys"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_EXCHANGE_BAD_CONFIGURATION, + "no keys"); } dki = TEH_KS_denomination_key_lookup_by_hash (key_state, &coin->denom_pub_hash, @@ -451,9 +448,10 @@ verify_and_execute_payback (struct MHD_Connection *connection, TEH_KS_release (key_state); TALER_LOG_WARNING ( "Denomination key in /payback request not in payback mode\n"); - return TEH_RESPONSE_reply_with_error (connection, - ec, - hc); + return TALER_MHD_reply_with_error (connection, + hc, + ec, + "denomination not allowing payback"); } TALER_amount_ntoh (&pc.value, &dki->issue.properties.value); @@ -465,9 +463,10 @@ verify_and_execute_payback (struct MHD_Connection *connection, { TALER_LOG_WARNING ("Invalid coin passed for /payback\n"); TEH_KS_release (key_state); - return TEH_RESPONSE_reply_signature_invalid (connection, - TALER_EC_PAYBACK_DENOMINATION_SIGNATURE_INVALID, - "denom_sig"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_FORBIDDEN, + TALER_EC_PAYBACK_DENOMINATION_SIGNATURE_INVALID, + "denom_sig"); } /* check payback request signature */ @@ -485,9 +484,10 @@ verify_and_execute_payback (struct MHD_Connection *connection, { TALER_LOG_WARNING ("Invalid signature on /payback request\n"); TEH_KS_release (key_state); - return TEH_RESPONSE_reply_signature_invalid (connection, - TALER_EC_PAYBACK_SIGNATURE_INVALID, - "coin_sig"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_FORBIDDEN, + TALER_EC_PAYBACK_SIGNATURE_INVALID, + "coin_sig"); } GNUNET_CRYPTO_hash (&coin->coin_pub.eddsa_pub, @@ -503,9 +503,10 @@ verify_and_execute_payback (struct MHD_Connection *connection, GNUNET_break (0); TEH_KS_release (key_state); - return TEH_RESPONSE_reply_internal_error (connection, - TALER_EC_PAYBACK_BLINDING_FAILED, - "coin_bks"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_PAYBACK_BLINDING_FAILED, + "coin_bks"); } TEH_KS_release (key_state); GNUNET_CRYPTO_hash (coin_ev, @@ -603,18 +604,18 @@ TEH_PAYBACK_handler_payback (struct TEH_RequestHandler *rh, }; (void) rh; - res = TEH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &json); + res = TALER_MHD_parse_post_json (connection, + connection_cls, + upload_data, + upload_data_size, + &json); if (GNUNET_SYSERR == res) return MHD_NO; if ( (GNUNET_NO == res) || (NULL == json) ) return MHD_YES; - res = TEH_PARSE_json_data (connection, - json, - spec); + res = TALER_MHD_parse_json_data (connection, + json, + spec); json_decref (json); if (GNUNET_SYSERR == res) return MHD_NO; /* hard failure */ diff --git a/src/exchange/taler-exchange-httpd_refresh_link.c b/src/exchange/taler-exchange-httpd_refresh_link.c index c51887a95..c3d36e29b 100644 --- a/src/exchange/taler-exchange-httpd_refresh_link.c +++ b/src/exchange/taler-exchange-httpd_refresh_link.c @@ -24,7 +24,7 @@ #include <gnunet/gnunet_util_lib.h> #include <jansson.h> #include <microhttpd.h> -#include "taler-exchange-httpd_parsing.h" +#include "taler_mhd_lib.h" #include "taler-exchange-httpd_mhd.h" #include "taler-exchange-httpd_refresh_link.h" #include "taler-exchange-httpd_responses.h" @@ -156,16 +156,18 @@ refresh_link_transaction (void *cls, ctx); if (NULL == ctx->mlist) { - *mhd_ret = TEH_RESPONSE_reply_internal_error (connection, - ctx->ec, - "coin_pub"); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + ctx->ec, + "coin_pub"); return GNUNET_DB_STATUS_HARD_ERROR; } if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) { - *mhd_ret = TEH_RESPONSE_reply_arg_unknown (connection, - TALER_EC_REFRESH_LINK_COIN_UNKNOWN, - "coin_pub"); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_REFRESH_LINK_COIN_UNKNOWN, + "coin_pub"); return GNUNET_DB_STATUS_HARD_ERROR; } return qs; @@ -201,11 +203,11 @@ TEH_REFRESH_handler_refresh_link (struct TEH_RequestHandler *rh, memset (&ctx, 0, sizeof (ctx)); - res = TEH_PARSE_mhd_request_arg_data (connection, - "coin_pub", - &ctx.coin_pub, - sizeof (struct - TALER_CoinSpendPublicKeyP)); + res = TALER_MHD_parse_request_arg_data (connection, + "coin_pub", + &ctx.coin_pub, + sizeof (struct + TALER_CoinSpendPublicKeyP)); if (GNUNET_SYSERR == res) return MHD_NO; if (GNUNET_OK != res) @@ -222,9 +224,9 @@ TEH_REFRESH_handler_refresh_link (struct TEH_RequestHandler *rh, json_decref (ctx.mlist); return mhd_ret; } - mhd_ret = TEH_RESPONSE_reply_json (connection, - ctx.mlist, - MHD_HTTP_OK); + mhd_ret = TALER_MHD_reply_json (connection, + ctx.mlist, + MHD_HTTP_OK); json_decref (ctx.mlist); return mhd_ret; } diff --git a/src/exchange/taler-exchange-httpd_refresh_melt.c b/src/exchange/taler-exchange-httpd_refresh_melt.c index a00fda14f..8fbb58513 100644 --- a/src/exchange/taler-exchange-httpd_refresh_melt.c +++ b/src/exchange/taler-exchange-httpd_refresh_melt.c @@ -24,7 +24,8 @@ #include <gnunet/gnunet_util_lib.h> #include <jansson.h> #include <microhttpd.h> -#include "taler-exchange-httpd_parsing.h" +#include "taler_json_lib.h" +#include "taler_mhd_lib.h" #include "taler-exchange-httpd_mhd.h" #include "taler-exchange-httpd_refresh_melt.h" #include "taler-exchange-httpd_responses.h" @@ -60,26 +61,28 @@ reply_refresh_melt_insufficient_funds (struct MHD_Connection *connection, history = TEH_RESPONSE_compile_transaction_history (tl); if (NULL == history) - return TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_REFRESH_MELT_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS); - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_FORBIDDEN, - "{s:s, s:I, s:o, s:o, s:o, s:o, s:o}", - "error", - "insufficient funds", - "code", - (json_int_t) - TALER_EC_REFRESH_MELT_INSUFFICIENT_FUNDS, - "coin_pub", - GNUNET_JSON_from_data_auto (coin_pub), - "original_value", - TALER_JSON_from_amount (&coin_value), - "residual_value", - TALER_JSON_from_amount (residual), - "requested_value", - TALER_JSON_from_amount (requested), - "history", - history); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_REFRESH_MELT_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS, + "Failed to compile transaction history"); + return TALER_MHD_reply_json_pack (connection, + MHD_HTTP_CONFLICT, + "{s:s, s:I, s:o, s:o, s:o, s:o, s:o}", + "error", + "insufficient funds", + "code", + (json_int_t) + TALER_EC_REFRESH_MELT_INSUFFICIENT_FUNDS, + "coin_pub", + GNUNET_JSON_from_data_auto (coin_pub), + "original_value", + TALER_JSON_from_amount (&coin_value), + "residual_value", + TALER_JSON_from_amount (residual), + "requested_value", + TALER_JSON_from_amount (requested), + "history", + history); } @@ -110,19 +113,20 @@ reply_refresh_melt_success (struct MHD_Connection *connection, &pub, &sig)) { - return TEH_RESPONSE_reply_internal_error (connection, - TALER_EC_EXCHANGE_BAD_CONFIGURATION, - "no keys"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_EXCHANGE_BAD_CONFIGURATION, + "no keys"); } sig_json = GNUNET_JSON_from_data_auto (&sig); GNUNET_assert (NULL != sig_json); - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:i, s:o, s:o}", - "noreveal_index", (int) noreveal_index, - "exchange_sig", sig_json, - "exchange_pub", - GNUNET_JSON_from_data_auto (&pub)); + return TALER_MHD_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:i, s:o, s:o}", + "noreveal_index", (int) noreveal_index, + "exchange_sig", sig_json, + "exchange_pub", + GNUNET_JSON_from_data_auto (&pub)); } @@ -189,8 +193,10 @@ refresh_check_melt (struct MHD_Connection *connection, if (0 > qs) { if (GNUNET_DB_STATUS_HARD_ERROR == qs) - *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_REFRESH_MELT_DB_FETCH_ERROR); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_REFRESH_MELT_DB_FETCH_ERROR, + "failed to fetch old coin history"); return qs; } if (rmc->zombie_required) @@ -211,9 +217,10 @@ refresh_check_melt (struct MHD_Connection *connection, GNUNET_break (0); TEH_plugin->free_coin_transaction_list (TEH_plugin->cls, tl); - *mhd_ret = TEH_RESPONSE_reply_external_error (connection, - TALER_EC_REFRESH_MELT_COIN_EXPIRED_NO_ZOMBIE, - "denomination expired"); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_REFRESH_MELT_COIN_EXPIRED_NO_ZOMBIE, + "denomination expired"); return GNUNET_DB_STATUS_HARD_ERROR; } } @@ -225,8 +232,10 @@ refresh_check_melt (struct MHD_Connection *connection, GNUNET_break (0); TEH_plugin->free_coin_transaction_list (TEH_plugin->cls, tl); - *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_REFRESH_MELT_COIN_HISTORY_COMPUTATION_FAILED); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_REFRESH_MELT_COIN_HISTORY_COMPUTATION_FAILED, + "failed to compute coin transaction history"); return GNUNET_DB_STATUS_HARD_ERROR; } @@ -310,8 +319,10 @@ refresh_melt_transaction (void *cls, if (0 > qs) { if (GNUNET_DB_STATUS_HARD_ERROR == qs) - *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_REFRESH_MELT_DB_FETCH_ERROR); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_REFRESH_MELT_DB_FETCH_ERROR, + "failed to fetch melt index"); return qs; } @@ -335,8 +346,10 @@ refresh_melt_transaction (void *cls, { if (GNUNET_DB_STATUS_SOFT_ERROR != qs) { - *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_REFRESH_MELT_DB_STORE_SESSION_ERROR); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_REFRESH_MELT_DB_STORE_SESSION_ERROR, + "failed to persist melt data"); return GNUNET_DB_STATUS_HARD_ERROR; } return qs; @@ -370,9 +383,10 @@ handle_refresh_melt (struct MHD_Connection *connection, &rmc->refresh_session.amount_with_fee) > 0) { GNUNET_break_op (0); - return TEH_RESPONSE_reply_external_error (connection, - TALER_EC_REFRESH_MELT_FEES_EXCEED_CONTRIBUTION, - "melt amount smaller than melting fee"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_REFRESH_MELT_FEES_EXCEED_CONTRIBUTION, + "melt amount smaller than melting fee"); } } @@ -398,9 +412,10 @@ handle_refresh_melt (struct MHD_Connection *connection, eddsa_pub)) { GNUNET_break_op (0); - return TEH_RESPONSE_reply_signature_invalid (connection, - TALER_EC_REFRESH_MELT_COIN_SIGNATURE_INVALID, - "confirm_sig"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_FORBIDDEN, + TALER_EC_REFRESH_MELT_COIN_SIGNATURE_INVALID, + "confirm_sig"); } } @@ -467,11 +482,11 @@ TEH_REFRESH_handler_refresh_melt (struct TEH_RequestHandler *rh, }; (void) rh; - res = TEH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &root); + res = TALER_MHD_parse_post_json (connection, + connection_cls, + upload_data, + upload_data_size, + &root); if (GNUNET_SYSERR == res) return MHD_NO; if ( (GNUNET_NO == res) || @@ -481,9 +496,9 @@ TEH_REFRESH_handler_refresh_melt (struct TEH_RequestHandler *rh, memset (&rmc, 0, sizeof (rmc)); - res = TEH_PARSE_json_data (connection, - root, - spec); + res = TALER_MHD_parse_json_data (connection, + root, + spec); json_decref (root); if (GNUNET_OK != res) return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; @@ -492,9 +507,10 @@ TEH_REFRESH_handler_refresh_melt (struct TEH_RequestHandler *rh, if (NULL == key_state) { TALER_LOG_ERROR ("Lacking keys to operate\n"); - res = TEH_RESPONSE_reply_internal_error (connection, - TALER_EC_EXCHANGE_BAD_CONFIGURATION, - "no keys"); + res = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_EXCHANGE_BAD_CONFIGURATION, + "no keys"); goto cleanup; } @@ -530,8 +546,10 @@ TEH_REFRESH_handler_refresh_melt (struct TEH_RequestHandler *rh, if (0 > qs) { GNUNET_break (0); - res = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_REFRESH_MELT_DB_FETCH_ERROR); + res = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_REFRESH_MELT_DB_FETCH_ERROR, + "failed to find information about old coin"); goto cleanup; } if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) @@ -566,9 +584,10 @@ TEH_REFRESH_handler_refresh_melt (struct TEH_RequestHandler *rh, if (NULL == rmc.dki) { TALER_LOG_WARNING ("Unknown denomination key in /refresh/melt request\n"); - res = TEH_RESPONSE_reply_with_error (connection, - ec, - hc); + res = TALER_MHD_reply_with_error (connection, + hc, + ec, + "unknown denomination"); goto cleanup; } @@ -579,9 +598,10 @@ TEH_REFRESH_handler_refresh_melt (struct TEH_RequestHandler *rh, GNUNET_break_op (0); GNUNET_JSON_parse_free (spec); TEH_KS_release (key_state); - return TEH_RESPONSE_reply_signature_invalid (connection, - TALER_EC_REFRESH_MELT_DENOMINATION_SIGNATURE_INVALID, - "denom_sig"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_FORBIDDEN, + TALER_EC_REFRESH_MELT_DENOMINATION_SIGNATURE_INVALID, + "denom_sig"); } /* run actual logic, now that the request was parsed */ diff --git a/src/exchange/taler-exchange-httpd_refresh_reveal.c b/src/exchange/taler-exchange-httpd_refresh_reveal.c index be5228dd9..fb2602c61 100644 --- a/src/exchange/taler-exchange-httpd_refresh_reveal.c +++ b/src/exchange/taler-exchange-httpd_refresh_reveal.c @@ -24,7 +24,7 @@ #include <gnunet/gnunet_util_lib.h> #include <jansson.h> #include <microhttpd.h> -#include "taler-exchange-httpd_parsing.h" +#include "taler_mhd_lib.h" #include "taler-exchange-httpd_mhd.h" #include "taler-exchange-httpd_refresh_reveal.h" #include "taler-exchange-httpd_responses.h" @@ -84,9 +84,9 @@ reply_refresh_reveal_success (struct MHD_Connection *connection, json_object_set_new (root, "ev_sigs", list); - ret = TEH_RESPONSE_reply_json (connection, - root, - MHD_HTTP_OK); + ret = TALER_MHD_reply_json (connection, + root, + MHD_HTTP_OK); json_decref (root); } return ret; @@ -105,15 +105,15 @@ static int reply_refresh_reveal_missmatch (struct MHD_Connection *connection, const struct TALER_RefreshCommitmentP *rc) { - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_CONFLICT, - "{s:s, s:I, s:o}", - "error", "commitment violation", - "code", - (json_int_t) - TALER_EC_REFRESH_REVEAL_COMMITMENT_VIOLATION, - "rc_expected", - GNUNET_JSON_from_data_auto (rc)); + return TALER_MHD_reply_json_pack (connection, + MHD_HTTP_CONFLICT, + "{s:s, s:I, s:o}", + "error", "commitment violation", + "code", + (json_int_t) + TALER_EC_REFRESH_REVEAL_COMMITMENT_VIOLATION, + "rc_expected", + GNUNET_JSON_from_data_auto (rc)); } @@ -258,8 +258,10 @@ refresh_reveal_preflight (void *cls, return qs; case GNUNET_DB_STATUS_HARD_ERROR: GNUNET_break (qs); - *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_REFRESH_REVEAL_DB_FETCH_REVEAL_ERROR); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_REFRESH_REVEAL_DB_FETCH_REVEAL_ERROR, + "failed to fetch reveal data"); rctx->preflight_ok = GNUNET_SYSERR; return GNUNET_DB_STATUS_HARD_ERROR; case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: @@ -308,9 +310,10 @@ refresh_reveal_transaction (void *cls, &refresh_melt); if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) { - *mhd_ret = TEH_RESPONSE_reply_arg_invalid (connection, - TALER_EC_REFRESH_REVEAL_SESSION_UNKNOWN, - "rc"); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_REFRESH_REVEAL_SESSION_UNKNOWN, + "rc"); return GNUNET_DB_STATUS_HARD_ERROR; } if (GNUNET_DB_STATUS_SOFT_ERROR == qs) @@ -319,8 +322,10 @@ refresh_reveal_transaction (void *cls, (refresh_melt.session.noreveal_index >= TALER_CNC_KAPPA) ) { GNUNET_break (0); - *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_REFRESH_REVEAL_DB_FETCH_SESSION_ERROR); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_REFRESH_REVEAL_DB_FETCH_SESSION_ERROR, + "failed to fetch valid challenge from database"); return GNUNET_DB_STATUS_HARD_ERROR; } @@ -437,9 +442,10 @@ refresh_reveal_transaction (void *cls, &total)) ) { GNUNET_break_op (0); - *mhd_ret = TEH_RESPONSE_reply_internal_error (connection, - TALER_EC_REFRESH_REVEAL_COST_CALCULATION_OVERFLOW, - "failed to add up refresh costs"); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_REFRESH_REVEAL_COST_CALCULATION_OVERFLOW, + "failed to add up refresh costs"); return GNUNET_DB_STATUS_HARD_ERROR; } } @@ -447,9 +453,10 @@ refresh_reveal_transaction (void *cls, &refresh_melt.session.amount_with_fee)) { GNUNET_break_op (0); - *mhd_ret = TEH_RESPONSE_reply_external_error (connection, - TALER_EC_REFRESH_REVEAL_AMOUNT_INSUFFICIENT, - "melted coin value is insufficient to cover cost of operation"); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_REFRESH_REVEAL_AMOUNT_INSUFFICIENT, + "melted coin value is insufficient to cover cost of operation"); return GNUNET_DB_STATUS_HARD_ERROR; } } @@ -501,8 +508,10 @@ refresh_reveal_persist (void *cls, } if (GNUNET_DB_STATUS_HARD_ERROR == qs) { - *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_REFRESH_REVEAL_DB_COMMIT_ERROR); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_REFRESH_REVEAL_DB_COMMIT_ERROR, + "failed to persist reveal data"); } return qs; } @@ -542,26 +551,29 @@ handle_refresh_reveal_json (struct MHD_Connection *connection, (0 == num_fresh_coins) ) { GNUNET_break_op (0); - return TEH_RESPONSE_reply_arg_invalid (connection, - TALER_EC_REFRESH_REVEAL_NEW_DENOMS_ARRAY_SIZE_EXCESSIVE, - "new_denoms_h"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_REFRESH_REVEAL_NEW_DENOMS_ARRAY_SIZE_EXCESSIVE, + "new_denoms_h"); } if (json_array_size (new_denoms_h_json) != json_array_size (coin_evs)) { GNUNET_break_op (0); - return TEH_RESPONSE_reply_arg_invalid (connection, - TALER_EC_REFRESH_REVEAL_NEW_DENOMS_ARRAY_SIZE_MISSMATCH, - "new_denoms/coin_evs"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_REFRESH_REVEAL_NEW_DENOMS_ARRAY_SIZE_MISSMATCH, + "new_denoms/coin_evs"); } if (json_array_size (new_denoms_h_json) != json_array_size (link_sigs_json)) { GNUNET_break_op (0); - return TEH_RESPONSE_reply_arg_invalid (connection, - TALER_EC_REFRESH_REVEAL_NEW_DENOMS_ARRAY_SIZE_MISSMATCH, - "new_denoms/link_sigs"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_REFRESH_REVEAL_NEW_DENOMS_ARRAY_SIZE_MISSMATCH, + "new_denoms/link_sigs"); } /* Parse transfer private keys array */ @@ -573,11 +585,11 @@ handle_refresh_reveal_json (struct MHD_Connection *connection, }; int res; - res = TEH_PARSE_json_array (connection, - tp_json, - trans_spec, - i, - -1); + res = TALER_MHD_parse_json_array (connection, + tp_json, + trans_spec, + i, + -1); if (GNUNET_OK != res) return (GNUNET_NO == res) ? MHD_YES : MHD_NO; } @@ -597,9 +609,10 @@ handle_refresh_reveal_json (struct MHD_Connection *connection, { TALER_LOG_ERROR ("Lacking keys to operate\n"); /* FIXME: use correct EC code! */ - return TEH_RESPONSE_reply_internal_error (connection, - TALER_EC_REFRESH_REVEAL_SIGNING_ERROR, - "exchange lacks keys"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_REFRESH_REVEAL_SIGNING_ERROR, + "exchange lacks keys"); } /* Parse denomination key hashes */ @@ -613,11 +626,11 @@ handle_refresh_reveal_json (struct MHD_Connection *connection, unsigned int hc; enum TALER_ErrorCode ec; - res = TEH_PARSE_json_array (connection, - new_denoms_h_json, - spec, - i, - -1); + res = TALER_MHD_parse_json_array (connection, + new_denoms_h_json, + spec, + i, + -1); if (GNUNET_OK != res) { TEH_KS_release (key_state); @@ -631,9 +644,10 @@ handle_refresh_reveal_json (struct MHD_Connection *connection, if (NULL == dkis[i]) { TEH_KS_release (key_state); - return TEH_RESPONSE_reply_with_error (connection, - ec, - hc); + return TALER_MHD_reply_with_error (connection, + hc, + ec, + "failed to find denomination key"); } GNUNET_assert (NULL != dkis[i]->denom_priv.rsa_private_key); } @@ -649,11 +663,11 @@ handle_refresh_reveal_json (struct MHD_Connection *connection, GNUNET_JSON_spec_end () }; - res = TEH_PARSE_json_array (connection, - coin_evs, - spec, - i, - -1); + res = TALER_MHD_parse_json_array (connection, + coin_evs, + spec, + i, + -1); if (GNUNET_OK != res) { for (unsigned int j = 0; j<i; j++) @@ -677,19 +691,24 @@ handle_refresh_reveal_json (struct MHD_Connection *connection, switch (qs) { case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - res = TEH_RESPONSE_reply_arg_invalid (connection, - TALER_EC_REFRESH_REVEAL_SESSION_UNKNOWN, - "rc"); + res = TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_REFRESH_REVEAL_SESSION_UNKNOWN, + "rc"); break; case GNUNET_DB_STATUS_HARD_ERROR: - res = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_REFRESH_REVEAL_DB_FETCH_SESSION_ERROR); + res = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_REFRESH_REVEAL_DB_FETCH_SESSION_ERROR, + "failed to fetch session data"); break; case GNUNET_DB_STATUS_SOFT_ERROR: default: GNUNET_break (0); /* should be impossible */ - res = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_INTERNAL_INVARIANT_FAILURE); + res = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_INTERNAL_INVARIANT_FAILURE, + "assertion failed"); break; } goto cleanup; @@ -704,11 +723,11 @@ handle_refresh_reveal_json (struct MHD_Connection *connection, }; int res; - res = TEH_PARSE_json_array (connection, - link_sigs_json, - link_spec, - i, - -1); + res = TALER_MHD_parse_json_array (connection, + link_sigs_json, + link_spec, + i, + -1); if (GNUNET_OK != res) return (GNUNET_NO == res) ? MHD_YES : MHD_NO; /* Check link_sigs[i] signature */ @@ -731,9 +750,10 @@ handle_refresh_reveal_json (struct MHD_Connection *connection, eddsa_pub)) { GNUNET_break_op (0); - res = TEH_RESPONSE_reply_signature_invalid (connection, - TALER_EC_REFRESH_REVEAL_LINK_SIGNATURE_INVALID, - "link_sig"); + res = TALER_MHD_reply_with_error (connection, + MHD_HTTP_FORBIDDEN, + TALER_EC_REFRESH_REVEAL_LINK_SIGNATURE_INVALID, + "link_sig"); goto cleanup; } } @@ -757,8 +777,10 @@ handle_refresh_reveal_json (struct MHD_Connection *connection, if (NULL == rctx->ev_sigs[i].rsa_signature) { GNUNET_break (0); - res = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_REFRESH_REVEAL_SIGNING_ERROR); + res = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_REFRESH_REVEAL_SIGNING_ERROR, + "internal signing error"); goto cleanup; } } @@ -879,11 +901,11 @@ TEH_REFRESH_handler_refresh_reveal (struct TEH_RequestHandler *rh, }; (void) rh; - res = TEH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &root); + res = TALER_MHD_parse_post_json (connection, + connection_cls, + upload_data, + upload_data_size, + &root); if (GNUNET_SYSERR == res) return MHD_NO; if ( (GNUNET_NO == res) || @@ -893,9 +915,9 @@ TEH_REFRESH_handler_refresh_reveal (struct TEH_RequestHandler *rh, memset (&rctx, 0, sizeof (rctx)); - res = TEH_PARSE_json_data (connection, - root, - spec); + res = TALER_MHD_parse_json_data (connection, + root, + spec); json_decref (root); if (GNUNET_OK != res) { @@ -909,9 +931,10 @@ TEH_REFRESH_handler_refresh_reveal (struct TEH_RequestHandler *rh, { GNUNET_JSON_parse_free (spec); GNUNET_break_op (0); - return TEH_RESPONSE_reply_arg_invalid (connection, - TALER_EC_REFRESH_REVEAL_CNC_TRANSFER_ARRAY_SIZE_INVALID, - "transfer_privs"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_REFRESH_REVEAL_CNC_TRANSFER_ARRAY_SIZE_INVALID, + "transfer_privs"); } res = handle_refresh_reveal_json (connection, &rctx, diff --git a/src/exchange/taler-exchange-httpd_refund.c b/src/exchange/taler-exchange-httpd_refund.c index 48532a2ce..6a96ff982 100644 --- a/src/exchange/taler-exchange-httpd_refund.c +++ b/src/exchange/taler-exchange-httpd_refund.c @@ -29,7 +29,7 @@ #include <microhttpd.h> #include <pthread.h> #include "taler_json_lib.h" -#include "taler-exchange-httpd_parsing.h" +#include "taler_mhd_lib.h" #include "taler-exchange-httpd_refund.h" #include "taler-exchange-httpd_responses.h" #include "taler-exchange-httpd_keystate.h" @@ -66,17 +66,17 @@ reply_refund_success (struct MHD_Connection *connection, &pub, &sig)) { - return TEH_RESPONSE_reply_internal_error (connection, - TALER_EC_EXCHANGE_BAD_CONFIGURATION, - "no keys"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_EXCHANGE_BAD_CONFIGURATION, + "no keys"); } - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:s, s:o, s:o}", - "status", "REFUND_OK", - "sig", GNUNET_JSON_from_data_auto (&sig), - "pub", GNUNET_JSON_from_data_auto ( - &pub)); + return TALER_MHD_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:s, s:o, s:o}", + "status", "REFUND_OK", + "sig", GNUNET_JSON_from_data_auto (&sig), + "pub", GNUNET_JSON_from_data_auto (&pub)); } @@ -94,11 +94,11 @@ reply_refund_failure (struct MHD_Connection *connection, unsigned int response_code, enum TALER_ErrorCode ec) { - return TEH_RESPONSE_reply_json_pack (connection, - response_code, - "{s:s, s:I}", - "status", "refund failure", - "code", (json_int_t) ec); + return TALER_MHD_reply_json_pack (connection, + response_code, + "{s:s, s:I}", + "hint", "refund failure", + "code", (json_int_t) ec); } @@ -114,15 +114,15 @@ static int reply_refund_conflict (struct MHD_Connection *connection, const struct TALER_EXCHANGEDB_TransactionList *tl) { - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_CONFLICT, - "{s:s, s:I, s:o}", - "status", "conflicting refund", - "code", - (json_int_t) TALER_EC_REFUND_CONFLICT, - "history", - TEH_RESPONSE_compile_transaction_history ( - tl)); + return TALER_MHD_reply_json_pack (connection, + MHD_HTTP_CONFLICT, + "{s:s, s:I, s:o}", + "hint", "conflicting refund", + "code", + (json_int_t) TALER_EC_REFUND_CONFLICT, + "history", + TEH_RESPONSE_compile_transaction_history ( + tl)); } @@ -259,8 +259,10 @@ refund_transaction (void *cls, TALER_LOG_WARNING ("Deposit to /refund was not found\n"); TEH_plugin->free_coin_transaction_list (TEH_plugin->cls, tl); - *mhd_ret = TEH_RESPONSE_reply_transaction_unknown (connection, - TALER_EC_REFUND_DEPOSIT_NOT_FOUND); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_REFUND_DEPOSIT_NOT_FOUND, + "deposit unknown"); return GNUNET_DB_STATUS_HARD_ERROR; } /* handle if conflicting refund found */ @@ -309,9 +311,10 @@ refund_transaction (void *cls, GNUNET_break (0); TEH_plugin->free_coin_transaction_list (TEH_plugin->cls, tl); - *mhd_ret = TEH_RESPONSE_reply_internal_error (connection, - TALER_EC_REFUND_DB_INCONSISTENT, - "database inconsistent"); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_REFUND_DB_INCONSISTENT, + "database inconsistent"); return qs; } if (GNUNET_DB_STATUS_SOFT_ERROR == qs) @@ -349,9 +352,10 @@ refund_transaction (void *cls, TALER_LOG_ERROR ("Lacking keys to operate\n"); TEH_plugin->free_coin_transaction_list (TEH_plugin->cls, tl); - *mhd_ret = TEH_RESPONSE_reply_internal_error (connection, - TALER_EC_EXCHANGE_BAD_CONFIGURATION, - "no keys"); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_EXCHANGE_BAD_CONFIGURATION, + "no keys"); return GNUNET_DB_STATUS_HARD_ERROR; } dki = TEH_KS_denomination_key_lookup_by_hash (mks, @@ -367,9 +371,10 @@ refund_transaction (void *cls, TEH_KS_release (mks); TEH_plugin->free_coin_transaction_list (TEH_plugin->cls, tl); - *mhd_ret = TEH_RESPONSE_reply_with_error (connection, - ec, - hc); + *mhd_ret = TALER_MHD_reply_with_error (connection, + hc, + ec, + "denomination not found, but coin known"); return GNUNET_DB_STATUS_HARD_ERROR; } TALER_amount_ntoh (&expect_fee, @@ -382,9 +387,10 @@ refund_transaction (void *cls, { TEH_plugin->free_coin_transaction_list (TEH_plugin->cls, tl); - *mhd_ret = TEH_RESPONSE_reply_arg_invalid (connection, - TALER_EC_REFUND_FEE_TOO_LOW, - "refund_fee"); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_REFUND_FEE_TOO_LOW, + "refund_fee"); return GNUNET_DB_STATUS_HARD_ERROR; } if (1 == fee_cmp) @@ -402,8 +408,10 @@ refund_transaction (void *cls, if (GNUNET_DB_STATUS_HARD_ERROR == qs) { TALER_LOG_WARNING ("Failed to store /refund information in database\n"); - *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_REFUND_STORE_DB_ERROR); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_REFUND_STORE_DB_ERROR, + "could not persist store information"); return qs; } /* Success or soft failure */ @@ -443,17 +451,19 @@ verify_and_execute_refund (struct MHD_Connection *connection, &refund->refund_fee) ) { GNUNET_break_op (0); - return TEH_RESPONSE_reply_arg_invalid (connection, - TALER_EC_REFUND_FEE_CURRENCY_MISSMATCH, - "refund_fee"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_REFUND_FEE_CURRENCY_MISSMATCH, + "refund_fee"); } if (-1 == TALER_amount_cmp (&refund->refund_amount, &refund->refund_fee) ) { GNUNET_break_op (0); - return TEH_RESPONSE_reply_arg_invalid (connection, - TALER_EC_REFUND_FEE_ABOVE_AMOUNT, - "refund_amount"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_REFUND_FEE_ABOVE_AMOUNT, + "refund_amount"); } if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_REFUND, @@ -462,9 +472,10 @@ verify_and_execute_refund (struct MHD_Connection *connection, &refund->merchant_pub.eddsa_pub)) { TALER_LOG_WARNING ("Invalid signature on /refund request\n"); - return TEH_RESPONSE_reply_signature_invalid (connection, - TALER_EC_REFUND_MERCHANT_SIGNATURE_INVALID, - "merchant_sig"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_FORBIDDEN, + TALER_EC_REFUND_MERCHANT_SIGNATURE_INVALID, + "merchant_sig"); } if (GNUNET_OK != TEH_DB_run_transaction (connection, @@ -514,18 +525,18 @@ TEH_REFUND_handler_refund (struct TEH_RequestHandler *rh, }; (void) rh; - res = TEH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &json); + res = TALER_MHD_parse_post_json (connection, + connection_cls, + upload_data, + upload_data_size, + &json); if (GNUNET_SYSERR == res) return MHD_NO; if ( (GNUNET_NO == res) || (NULL == json) ) return MHD_YES; - res = TEH_PARSE_json_data (connection, - json, - spec); + res = TALER_MHD_parse_json_data (connection, + json, + spec); json_decref (json); if (GNUNET_SYSERR == res) return MHD_NO; /* hard failure */ diff --git a/src/exchange/taler-exchange-httpd_reserve_status.c b/src/exchange/taler-exchange-httpd_reserve_status.c index 4f9761485..60cdd4f5a 100644 --- a/src/exchange/taler-exchange-httpd_reserve_status.c +++ b/src/exchange/taler-exchange-httpd_reserve_status.c @@ -23,8 +23,9 @@ #include "platform.h" #include <gnunet/gnunet_util_lib.h> #include <jansson.h> +#include "taler_mhd_lib.h" +#include "taler_json_lib.h" #include "taler-exchange-httpd_reserve_status.h" -#include "taler-exchange-httpd_parsing.h" #include "taler-exchange-httpd_responses.h" #include "taler-exchange-httpd_keystate.h" @@ -47,15 +48,16 @@ reply_reserve_status_success (struct MHD_Connection *connection, json_history = TEH_RESPONSE_compile_reserve_history (rh, &balance); if (NULL == json_history) - return TEH_RESPONSE_reply_internal_error (connection, - TALER_EC_RESERVE_STATUS_DB_ERROR, - "balance calculation failure"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_RESERVE_STATUS_DB_ERROR, + "balance calculation failure"); json_balance = TALER_JSON_from_amount (&balance); - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:o, s:o}", - "balance", json_balance, - "history", json_history); + return TALER_MHD_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:o, s:o}", + "balance", json_balance, + "history", json_history); } @@ -135,11 +137,11 @@ TEH_RESERVE_handler_reserve_status (struct TEH_RequestHandler *rh, int res; int mhd_ret; - res = TEH_PARSE_mhd_request_arg_data (connection, - "reserve_pub", - &rsc.reserve_pub, - sizeof (struct - TALER_ReservePublicKeyP)); + res = TALER_MHD_parse_request_arg_data (connection, + "reserve_pub", + &rsc.reserve_pub, + sizeof (struct + TALER_ReservePublicKeyP)); if (GNUNET_SYSERR == res) return MHD_NO; /* internal error */ if (GNUNET_NO == res) @@ -155,14 +157,14 @@ TEH_RESERVE_handler_reserve_status (struct TEH_RequestHandler *rh, /* generate proper response */ if (NULL == rsc.rh) - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_NOT_FOUND, - "{s:s, s:s, s:I}", - "error", "Reserve not found", - "parameter", "withdraw_pub", - "code", - (json_int_t) - TALER_EC_RESERVE_STATUS_UNKNOWN); + return TALER_MHD_reply_json_pack (connection, + MHD_HTTP_NOT_FOUND, + "{s:s, s:s, s:I}", + "error", "Reserve not found", + "parameter", "withdraw_pub", + "code", + (json_int_t) + TALER_EC_RESERVE_STATUS_UNKNOWN); mhd_ret = reply_reserve_status_success (connection, rsc.rh); TEH_plugin->free_reserve_history (TEH_plugin->cls, diff --git a/src/exchange/taler-exchange-httpd_reserve_withdraw.c b/src/exchange/taler-exchange-httpd_reserve_withdraw.c index 578aace31..8b59817a7 100644 --- a/src/exchange/taler-exchange-httpd_reserve_withdraw.c +++ b/src/exchange/taler-exchange-httpd_reserve_withdraw.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2017 GNUnet e.V. + Copyright (C) 2014-2019 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 @@ -16,7 +16,6 @@ Public License along with TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ - /** * @file taler-exchange-httpd_reserve_withdraw.c * @brief Handle /reserve/withdraw requests @@ -27,8 +26,9 @@ #include "platform.h" #include <gnunet/gnunet_util_lib.h> #include <jansson.h> +#include "taler_json_lib.h" +#include "taler_mhd_lib.h" #include "taler-exchange-httpd_reserve_withdraw.h" -#include "taler-exchange-httpd_parsing.h" #include "taler-exchange-httpd_responses.h" #include "taler-exchange-httpd_keystate.h" @@ -65,20 +65,21 @@ reply_reserve_withdraw_insufficient_funds (struct MHD_Connection *connection, /* Address the case where the ptr is not null, but * it fails "internally" to dump as string (= corrupted). */ || (0 == json_dumpb (json_history, NULL, 0, 0))) - return TEH_RESPONSE_reply_internal_error (connection, - TALER_EC_WITHDRAW_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS, - "balance calculation failure"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_WITHDRAW_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS, + "balance calculation failure"); json_balance = TALER_JSON_from_amount (&balance); - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_FORBIDDEN, - "{s:s, s:I, s:o, s:o}", - "error", "Insufficient funds", - "code", - (json_int_t) - TALER_EC_WITHDRAW_INSUFFICIENT_FUNDS, - "balance", json_balance, - "history", json_history); + return TALER_MHD_reply_json_pack (connection, + MHD_HTTP_CONFLICT, + "{s:s, s:I, s:o, s:o}", + "error", "Insufficient funds", + "code", + (json_int_t) + TALER_EC_WITHDRAW_INSUFFICIENT_FUNDS, + "balance", json_balance, + "history", json_history); } @@ -98,10 +99,10 @@ reply_reserve_withdraw_success (struct MHD_Connection *connection, json_t *sig_json; sig_json = GNUNET_JSON_from_rsa_signature (collectable->sig.rsa_signature); - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:o}", - "ev_sig", sig_json); + return TALER_MHD_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:o}", + "ev_sig", sig_json); } @@ -209,8 +210,10 @@ withdraw_transaction (void *cls, { GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); if (GNUNET_DB_STATUS_HARD_ERROR == qs) - *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_WITHDRAW_DB_FETCH_ERROR); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_WITHDRAW_DB_FETCH_ERROR, + "failed to fetch withdraw data"); wc->collectable.sig = denom_sig; return qs; } @@ -252,15 +255,18 @@ withdraw_transaction (void *cls, if (0 > qs) { if (GNUNET_DB_STATUS_HARD_ERROR == qs) - *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_WITHDRAW_DB_FETCH_ERROR); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_WITHDRAW_DB_FETCH_ERROR, + "failed to fetch reserve data"); return qs; } if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) { - *mhd_ret = TEH_RESPONSE_reply_arg_unknown (connection, - TALER_EC_WITHDRAW_RESERVE_UNKNOWN, - "reserve_pub"); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_WITHDRAW_RESERVE_UNKNOWN, + "reserve_pub"); return GNUNET_DB_STATUS_HARD_ERROR; } if (0 < TALER_amount_cmp (&wc->amount_required, @@ -286,8 +292,10 @@ withdraw_transaction (void *cls, if (NULL == rh) { if (GNUNET_DB_STATUS_HARD_ERROR == qs) - *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_WITHDRAW_DB_FETCH_ERROR); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_WITHDRAW_DB_FETCH_ERROR, + "failed to fetch reserve history"); return GNUNET_DB_STATUS_HARD_ERROR; } *mhd_ret = reply_reserve_withdraw_insufficient_funds (connection, @@ -308,9 +316,10 @@ withdraw_transaction (void *cls, if (NULL == wc->collectable.sig.rsa_signature) { GNUNET_break (0); - *mhd_ret = TEH_RESPONSE_reply_internal_error (connection, - TALER_EC_WITHDRAW_SIGNATURE_FAILED, - "Internal error"); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_WITHDRAW_SIGNATURE_FAILED, + "Failed to create signature"); return GNUNET_DB_STATUS_HARD_ERROR; } } @@ -330,8 +339,10 @@ withdraw_transaction (void *cls, { GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); if (GNUNET_DB_STATUS_HARD_ERROR == qs) - *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_WITHDRAW_DB_STORE_ERROR); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_WITHDRAW_DB_STORE_ERROR, + "failed to persist withdraw data"); return qs; } return qs; @@ -383,18 +394,18 @@ TEH_RESERVE_handler_reserve_withdraw (struct TEH_RequestHandler *rh, }; (void) rh; - res = TEH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &root); + res = TALER_MHD_parse_post_json (connection, + connection_cls, + upload_data, + upload_data_size, + &root); if (GNUNET_SYSERR == res) return MHD_NO; if ( (GNUNET_NO == res) || (NULL == root) ) return MHD_YES; - res = TEH_PARSE_json_data (connection, - root, - spec); + res = TALER_MHD_parse_json_data (connection, + root, + spec); json_decref (root); if (GNUNET_OK != res) return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; @@ -403,9 +414,10 @@ TEH_RESERVE_handler_reserve_withdraw (struct TEH_RequestHandler *rh, { TALER_LOG_ERROR ("Lacking keys to operate\n"); GNUNET_JSON_parse_free (spec); - return TEH_RESPONSE_reply_internal_error (connection, - TALER_EC_EXCHANGE_BAD_CONFIGURATION, - "no keys"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_EXCHANGE_BAD_CONFIGURATION, + "no keys"); } wc.dki = TEH_KS_denomination_key_lookup_by_hash (wc.key_state, &wc.denom_pub_hash, @@ -416,9 +428,10 @@ TEH_RESERVE_handler_reserve_withdraw (struct TEH_RequestHandler *rh, { GNUNET_JSON_parse_free (spec); TEH_KS_release (wc.key_state); - return TEH_RESPONSE_reply_with_error (connection, - ec, - hc); + return TALER_MHD_reply_with_error (connection, + hc, + ec, + "could not find denomination key"); } GNUNET_assert (NULL != wc.dki->denom_priv.rsa_private_key); TALER_amount_ntoh (&amount, @@ -432,9 +445,10 @@ TEH_RESERVE_handler_reserve_withdraw (struct TEH_RequestHandler *rh, { GNUNET_JSON_parse_free (spec); TEH_KS_release (wc.key_state); - return TEH_RESPONSE_reply_internal_error (connection, - TALER_EC_WITHDRAW_AMOUNT_FEE_OVERFLOW, - "amount overflow for value plus withdraw fee"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_WITHDRAW_AMOUNT_FEE_OVERFLOW, + "amount overflow for value plus withdraw fee"); } TALER_amount_hton (&wc.wsrd.amount_with_fee, &wc.amount_required); @@ -460,9 +474,10 @@ TEH_RESERVE_handler_reserve_withdraw (struct TEH_RequestHandler *rh, "Client supplied invalid signature for /reserve/withdraw request\n"); GNUNET_JSON_parse_free (spec); TEH_KS_release (wc.key_state); - return TEH_RESPONSE_reply_signature_invalid (connection, - TALER_EC_WITHDRAW_RESERVE_SIGNATURE_INVALID, - "reserve_sig"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_FORBIDDEN, + TALER_EC_WITHDRAW_RESERVE_SIGNATURE_INVALID, + "reserve_sig"); } #if OPTIMISTIC_SIGN @@ -476,9 +491,10 @@ TEH_RESERVE_handler_reserve_withdraw (struct TEH_RequestHandler *rh, GNUNET_break (0); GNUNET_JSON_parse_free (spec); TEH_KS_release (wc.key_state); - return TEH_RESPONSE_reply_internal_error (connection, - TALER_EC_WITHDRAW_SIGNATURE_FAILED, - "Internal error"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_WITHDRAW_SIGNATURE_FAILED, + "Failed to sign"); } #endif diff --git a/src/exchange/taler-exchange-httpd_responses.c b/src/exchange/taler-exchange-httpd_responses.c index 048a8bef0..4ef0f2d15 100644 --- a/src/exchange/taler-exchange-httpd_responses.c +++ b/src/exchange/taler-exchange-httpd_responses.c @@ -27,6 +27,7 @@ #include "taler-exchange-httpd_responses.h" #include "taler_util.h" #include "taler_json_lib.h" +#include "taler_mhd_lib.h" #include "taler-exchange-httpd_keystate.h" /** @@ -39,453 +40,6 @@ /** - * Add headers we want to return in every response. - * Useful for testing, like if we want to always close - * connections. - * - * @param response response to modify - */ -void -TEH_RESPONSE_add_global_headers (struct MHD_Response *response) -{ - if (TEH_exchange_connection_close) - GNUNET_break (MHD_YES == - MHD_add_response_header (response, - MHD_HTTP_HEADER_CONNECTION, - "close")); -} - - -/** - * Is HTTP body deflate compression supported by the client? - * - * @param connection connection to check - * @return #MHD_YES if 'deflate' compression is allowed - * - * Note that right now we're ignoring q-values, which is technically - * not correct, and also do not support "*" anywhere but in a line by - * itself. This should eventually be fixed, see also - * https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html - */ -int -TEH_RESPONSE_can_compress (struct MHD_Connection *connection) -{ - const char *ae; - const char *de; - - ae = MHD_lookup_connection_value (connection, - MHD_HEADER_KIND, - MHD_HTTP_HEADER_ACCEPT_ENCODING); - if (NULL == ae) - return MHD_NO; - if (0 == strcmp (ae, - "*")) - return MHD_YES; - de = strstr (ae, - "deflate"); - if (NULL == de) - return MHD_NO; - if ( ( (de == ae) || - (de[-1] == ',') || - (de[-1] == ' ') ) && - ( (de[strlen ("deflate")] == '\0') || - (de[strlen ("deflate")] == ',') || - (de[strlen ("deflate")] == ';') ) ) - return MHD_YES; - return MHD_NO; -} - - -/** - * Try to compress a response body. Updates @a buf and @a buf_size. - * - * @param[in,out] buf pointer to body to compress - * @param[in,out] buf_size pointer to initial size of @a buf - * @return #MHD_YES if @a buf was compressed - */ -int -TEH_RESPONSE_body_compress (void **buf, - size_t *buf_size) -{ - Bytef *cbuf; - uLongf cbuf_size; - int ret; - - cbuf_size = compressBound (*buf_size); - cbuf = malloc (cbuf_size); - if (NULL == cbuf) - return MHD_NO; - ret = compress (cbuf, - &cbuf_size, - (const Bytef *) *buf, - *buf_size); - if ( (Z_OK != ret) || - (cbuf_size >= *buf_size) ) - { - /* compression failed */ - free (cbuf); - return MHD_NO; - } - free (*buf); - *buf = (void *) cbuf; - *buf_size = (size_t) cbuf_size; - return MHD_YES; -} - - -/** - * Send JSON object as response. - * - * @param connection the MHD connection - * @param json the json object - * @param response_code the http response code - * @return MHD result code - */ -int -TEH_RESPONSE_reply_json (struct MHD_Connection *connection, - const json_t *json, - unsigned int response_code) -{ - struct MHD_Response *resp; - void *json_str; - size_t json_len; - int ret; - int comp; - - json_str = json_dumps (json, - JSON_INDENT (2)); - if (NULL == json_str) - { - /** - * This log helps to figure out which - * function called this one and assert-failed. - */ - TALER_LOG_ERROR ("Aborting json-packing for HTTP code: %u\n", - response_code); - - GNUNET_assert (0); - return MHD_NO; - } - json_len = strlen (json_str); - /* try to compress the body */ - comp = MHD_NO; - if (MHD_YES == - TEH_RESPONSE_can_compress (connection)) - comp = TEH_RESPONSE_body_compress (&json_str, - &json_len); - resp = MHD_create_response_from_buffer (json_len, - json_str, - MHD_RESPMEM_MUST_FREE); - if (NULL == resp) - { - free (json_str); - GNUNET_break (0); - return MHD_NO; - } - TEH_RESPONSE_add_global_headers (resp); - GNUNET_break (MHD_YES == - MHD_add_response_header (resp, - MHD_HTTP_HEADER_CONTENT_TYPE, - "application/json")); - if (MHD_YES == comp) - { - /* Need to indicate to client that body is compressed */ - if (MHD_NO == - MHD_add_response_header (resp, - MHD_HTTP_HEADER_CONTENT_ENCODING, - "deflate")) - { - GNUNET_break (0); - MHD_destroy_response (resp); - return MHD_NO; - } - } - ret = MHD_queue_response (connection, - response_code, - resp); - MHD_destroy_response (resp); - return ret; -} - - -/** - * Function to call to handle the request by building a JSON - * reply from a format string and varargs. - * - * @param connection the MHD connection to handle - * @param response_code HTTP response code to use - * @param fmt format string for pack - * @param ... varargs - * @return MHD result code - */ -int -TEH_RESPONSE_reply_json_pack (struct MHD_Connection *connection, - unsigned int response_code, - const char *fmt, - ...) -{ - json_t *json; - va_list argp; - int ret; - json_error_t jerror; - - va_start (argp, fmt); - json = json_vpack_ex (&jerror, 0, fmt, argp); - va_end (argp); - if (NULL == json) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to pack JSON with format `%s': %s\n", - fmt, - jerror.text); - GNUNET_break (0); - return MHD_NO; - } - ret = TEH_RESPONSE_reply_json (connection, - json, - response_code); - json_decref (json); - return ret; -} - - -/** - * Send a response indicating an invalid argument. - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @param param_name the parameter that is invalid - * @return a MHD result code - */ -int -TEH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection, - enum TALER_ErrorCode ec, - const char *param_name) -{ - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:I, s:s}", - "error", "invalid parameter", - "code", (json_int_t) ec, - "parameter", param_name); -} - - -/** - * Send a response indicating an argument refering to a - * resource unknown to the exchange (i.e. unknown reserve or - * denomination key). - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @param param_name the parameter that is invalid - * @return a MHD result code - */ -int -TEH_RESPONSE_reply_arg_unknown (struct MHD_Connection *connection, - enum TALER_ErrorCode ec, - const char *param_name) -{ - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_NOT_FOUND, - "{s:s, s:I, s:s}", - "error", "unknown entity referenced", - "code", (json_int_t) ec, - "parameter", param_name); -} - - -/** - * Send a response indicating an invalid signature. - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @param param_name the parameter that is invalid - * @return a MHD result code - */ -int -TEH_RESPONSE_reply_signature_invalid (struct MHD_Connection *connection, - enum TALER_ErrorCode ec, - const char *param_name) -{ - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_UNAUTHORIZED, - "{s:s, s:I, s:s}", - "error", "invalid signature", - "code", (json_int_t) ec, - "parameter", param_name); -} - - -/** - * Send a response indicating a missing argument. - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @param param_name the parameter that is missing - * @return a MHD result code - */ -int -TEH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection, - enum TALER_ErrorCode ec, - const char *param_name) -{ - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:I, s:s}", - "error", "missing parameter", - "code", (json_int_t) ec, - "parameter", param_name); -} - - -/** - * Send a response indicating an internal error. - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @param hint hint about the internal error's nature - * @return a MHD result code - */ -int -TEH_RESPONSE_reply_internal_error (struct MHD_Connection *connection, - enum TALER_ErrorCode ec, - const char *hint) -{ - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - "{s:s, s:I, s:s}", - "error", "internal error", - "code", (json_int_t) ec, - "hint", hint); -} - - -/** - * Send a response indicating an error. - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @param http_status HTTP status code to use - * @return a MHD result code - */ -int -TEH_RESPONSE_reply_with_error (struct MHD_Connection *connection, - enum TALER_ErrorCode ec, - unsigned int http_status) -{ - return TEH_RESPONSE_reply_json_pack (connection, - http_status, - "{s:I}", - "code", (json_int_t) ec); -} - - -/** - * Send a response indicating an external error. - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @param hint hint about the error's nature - * @return a MHD result code - */ -int -TEH_RESPONSE_reply_external_error (struct MHD_Connection *connection, - enum TALER_ErrorCode ec, - const char *hint) -{ - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:I, s:s}", - "error", "client error", - "code", (json_int_t) ec, - "hint", hint); -} - - -/** - * Send a response indicating an error committing a - * transaction (concurrent interference). - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @return a MHD result code - */ -int -TEH_RESPONSE_reply_commit_error (struct MHD_Connection *connection, - enum TALER_ErrorCode ec) -{ - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - "{s:s, s:I}", - "error", "commit failure", - "code", (json_int_t) ec); -} - - -/** - * Send a response indicating a failure to talk to the Exchange's - * database. - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @return a MHD result code - */ -int -TEH_RESPONSE_reply_internal_db_error (struct MHD_Connection *connection, - enum TALER_ErrorCode ec) -{ - return TEH_RESPONSE_reply_internal_error (connection, - ec, - "Failure in database interaction"); -} - - -/** - * Send a response indicating that the request was too big. - * - * @param connection the MHD connection to use - * @return a MHD result code - */ -int -TEH_RESPONSE_reply_request_too_large (struct MHD_Connection *connection) -{ - struct MHD_Response *resp; - int ret; - - resp = MHD_create_response_from_buffer (0, - NULL, - MHD_RESPMEM_PERSISTENT); - if (NULL == resp) - return MHD_NO; - TEH_RESPONSE_add_global_headers (resp); - ret = MHD_queue_response (connection, - MHD_HTTP_REQUEST_ENTITY_TOO_LARGE, - resp); - MHD_destroy_response (resp); - return ret; -} - - -/** - * Send a response indicating that the JSON was malformed. - * - * @param connection the MHD connection to use - * @return a MHD result code - */ -int -TEH_RESPONSE_reply_invalid_json (struct MHD_Connection *connection) -{ - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:I}", - "error", "invalid json", - "code", - (json_int_t) TALER_EC_JSON_INVALID); -} - - -/** * Compile the transaction history of a coin into a JSON object. * * @param tl transaction history to JSON-ify @@ -874,15 +428,16 @@ TEH_RESPONSE_reply_coin_insufficient_funds (struct MHD_Connection *connection, history = TEH_RESPONSE_compile_transaction_history (tl); if (NULL == history) - return TEH_RESPONSE_reply_internal_error (connection, - TALER_EC_COIN_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS, - "failed to convert transaction history to JSON"); - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_FORBIDDEN, - "{s:s, s:I, s:o}", - "error", "insufficient funds", - "code", (json_int_t) ec, - "history", history); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_COIN_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS, + "failed to convert transaction history to JSON"); + return TALER_MHD_reply_json_pack (connection, + MHD_HTTP_CONFLICT, + "{s:s, s:I, s:o}", + "error", "insufficient funds", + "code", (json_int_t) ec, + "history", history); } @@ -1170,25 +725,4 @@ TEH_RESPONSE_compile_reserve_history (const struct } -/** - * A merchant asked for details about a deposit, but - * we do not know anything about the deposit. Generate the - * 404 reply. - * - * @param connection connection to the client - * @param ec Taler error code - * @return MHD result code - */ -int -TEH_RESPONSE_reply_transaction_unknown (struct MHD_Connection *connection, - enum TALER_ErrorCode ec) -{ - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_NOT_FOUND, - "{s:s, s:I}", - "error", "Deposit unknown", - "code", (json_int_t) ec); -} - - /* end of taler-exchange-httpd_responses.c */ diff --git a/src/exchange/taler-exchange-httpd_responses.h b/src/exchange/taler-exchange-httpd_responses.h index 9b6a78859..ec0515829 100644 --- a/src/exchange/taler-exchange-httpd_responses.h +++ b/src/exchange/taler-exchange-httpd_responses.h @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014 GNUnet e.V. + Copyright (C) 2014-2019 GNUnet e.V. 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 @@ -13,7 +13,6 @@ You should have received a copy of the GNU Affero General Public License along with TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ - /** * @file taler-exchange-httpd_responses.h * @brief API for generating generic replies of the exchange; these @@ -35,216 +34,6 @@ /** - * Add headers we want to return in every response. - * Useful for testing, like if we want to always close - * connections. - * - * @param response response to modify - */ -void -TEH_RESPONSE_add_global_headers (struct MHD_Response *response); - - -/** - * Try to compress a response body. Updates @a buf and @a buf_size. - * - * @param[in,out] buf pointer to body to compress - * @param[in,out] buf_size pointer to initial size of @a buf - * @return #MHD_YES if @a buf was compressed - */ -int -TEH_RESPONSE_body_compress (void **buf, - size_t *buf_size); - - -/** - * Is HTTP body deflate compression supported by the client? - * - * @param connection connection to check - * @return #MHD_YES if 'deflate' compression is allowed - */ -int -TEH_RESPONSE_can_compress (struct MHD_Connection *connection); - - -/** - * Send JSON object as response. - * - * @param connection the MHD connection - * @param json the json object - * @param response_code the http response code - * @return MHD result code - */ -int -TEH_RESPONSE_reply_json (struct MHD_Connection *connection, - const json_t *json, - unsigned int response_code); - - -/** - * Function to call to handle the request by building a JSON - * reply from a format string and varargs. - * - * @param connection the MHD connection to handle - * @param response_code HTTP response code to use - * @param fmt format string for pack - * @param ... varargs - * @return MHD result code - */ -int -TEH_RESPONSE_reply_json_pack (struct MHD_Connection *connection, - unsigned int response_code, - const char *fmt, - ...); - - -/** - * Send a response indicating an invalid signature. - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @param param_name the parameter that is invalid - * @return a MHD result code - */ -int -TEH_RESPONSE_reply_signature_invalid (struct MHD_Connection *connection, - enum TALER_ErrorCode ec, - const char *param_name); - - -/** - * Send a response indicating an invalid argument. - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @param param_name the parameter that is invalid - * @return MHD result code - */ -int -TEH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection, - enum TALER_ErrorCode ec, - const char *param_name); - - -/** - * Send a response indicating an argument refering to a - * resource unknown to the exchange (i.e. unknown reserve or - * denomination key). - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @param param_name the parameter that is invalid - * @return a MHD result code - */ -int -TEH_RESPONSE_reply_arg_unknown (struct MHD_Connection *connection, - enum TALER_ErrorCode ec, - const char *param_name); - - -/** - * Send a response indicating a missing argument. - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @param param_name the parameter that is missing - * @return a MHD result code - */ -int -TEH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection, - enum TALER_ErrorCode ec, - const char *param_name); - - -/** - * Send a response indicating an internal error. - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @param hint hint about the internal error's nature - * @return a MHD result code - */ -int -TEH_RESPONSE_reply_internal_error (struct MHD_Connection *connection, - enum TALER_ErrorCode ec, - const char *hint); - - -/** - * Send a response indicating an error. - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @param http_status HTTP status code to use - * @return a MHD result code - */ -int -TEH_RESPONSE_reply_with_error (struct MHD_Connection *connection, - enum TALER_ErrorCode ec, - unsigned int http_status); - - -/** - * Send a response indicating an external error. - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @param hint hint about the error's nature - * @return a MHD result code - */ -int -TEH_RESPONSE_reply_external_error (struct MHD_Connection *connection, - enum TALER_ErrorCode ec, - const char *hint); - - -/** - * Send a response indicating an error committing a - * transaction (concurrent interference). - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @return a MHD result code - */ -int -TEH_RESPONSE_reply_commit_error (struct MHD_Connection *connection, - enum TALER_ErrorCode ec); - - -/** - * Send a response indicating a failure to talk to the Exchange's - * database. - * - * @param connection the MHD connection to use - * @param ec error code uniquely identifying the error - * @return a MHD result code - */ -int -TEH_RESPONSE_reply_internal_db_error (struct MHD_Connection *connection, - enum TALER_ErrorCode ec); - - -/** - * Send a response indicating that the request was too big. - * - * @param connection the MHD connection to use - * @return a MHD result code - */ -int -TEH_RESPONSE_reply_request_too_large (struct MHD_Connection *connection); - - -/** - * Send a response indicating that the JSON was malformed. - * - * @param connection the MHD connection to use - * @return a MHD result code - */ -int -TEH_RESPONSE_reply_invalid_json (struct MHD_Connection *connectionx); - - -/** * Compile the history of a reserve into a JSON object * and calculate the total balance. * @@ -277,20 +66,6 @@ TEH_RESPONSE_reply_coin_insufficient_funds (struct MHD_Connection *connection, /** - * A merchant asked for details about a deposit, but - * we do not know anything about the deposit. Generate the - * 404 reply. - * - * @param connection connection to the client - * @param ec Taler error code - * @return MHD result code - */ -int -TEH_RESPONSE_reply_transaction_unknown (struct MHD_Connection *connection, - enum TALER_ErrorCode ec); - - -/** * Compile the transaction history of a coin into a JSON object. * * @param tl transaction history to JSON-ify diff --git a/src/exchange/taler-exchange-httpd_test.c b/src/exchange/taler-exchange-httpd_test.c index 0a64f267f..4b3c50b2c 100644 --- a/src/exchange/taler-exchange-httpd_test.c +++ b/src/exchange/taler-exchange-httpd_test.c @@ -24,9 +24,9 @@ #include <gnunet/gnunet_json_lib.h> #include <jansson.h> #include <microhttpd.h> +#include "taler_mhd_lib.h" #include "taler_signatures.h" #include "taler-exchange-httpd_test.h" -#include "taler-exchange-httpd_parsing.h" #include "taler-exchange-httpd_responses.h" @@ -69,18 +69,18 @@ TEH_TEST_handler_test_base32 (struct TEH_RequestHandler *rh, }; (void) rh; - res = TEH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &json); + res = TALER_MHD_parse_post_json (connection, + connection_cls, + upload_data, + upload_data_size, + &json); if (GNUNET_SYSERR == res) return MHD_NO; if ( (GNUNET_NO == res) || (NULL == json) ) return MHD_YES; - res = TEH_PARSE_json_data (connection, - json, - spec); + res = TALER_MHD_parse_json_data (connection, + json, + spec); if (GNUNET_YES != res) return (GNUNET_NO == res) ? MHD_YES : MHD_NO; GNUNET_CRYPTO_hash (in_ptr, @@ -88,11 +88,11 @@ TEH_TEST_handler_test_base32 (struct TEH_RequestHandler *rh, &hc); GNUNET_JSON_parse_free (spec); json_decref (json); - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:o}", - "output", - GNUNET_JSON_from_data_auto (&hc)); + return TALER_MHD_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:o}", + "output", + GNUNET_JSON_from_data_auto (&hc)); } @@ -134,18 +134,18 @@ TEH_TEST_handler_test_encrypt (struct TEH_RequestHandler *rh, }; char *out; - res = TEH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &json); + res = TALER_MHD_parse_post_json (connection, + connection_cls, + upload_data, + upload_data_size, + &json); if (GNUNET_SYSERR == res) return MHD_NO; if ( (GNUNET_NO == res) || (NULL == json) ) return MHD_YES; - res = TEH_PARSE_json_data (connection, - json, - spec); + res = TALER_MHD_parse_json_data (connection, + json, + spec); json_decref (json); if (GNUNET_YES != res) return (GNUNET_NO == res) ? MHD_YES : MHD_NO; @@ -172,11 +172,11 @@ TEH_TEST_handler_test_encrypt (struct TEH_RequestHandler *rh, in_ptr_size); GNUNET_free (out); GNUNET_JSON_parse_free (spec); - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:o}", - "output", - json); + return TALER_MHD_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:o}", + "output", + json); } @@ -214,18 +214,18 @@ TEH_TEST_handler_test_hkdf (struct TEH_RequestHandler *rh, GNUNET_JSON_spec_end () }; - res = TEH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &json); + res = TALER_MHD_parse_post_json (connection, + connection_cls, + upload_data, + upload_data_size, + &json); if (GNUNET_SYSERR == res) return MHD_NO; if ( (GNUNET_NO == res) || (NULL == json) ) return MHD_YES; - res = TEH_PARSE_json_data (connection, - json, - spec); + res = TALER_MHD_parse_json_data (connection, + json, + spec); json_decref (json); if (GNUNET_YES != res) return (GNUNET_NO == res) ? MHD_YES : MHD_NO; @@ -237,11 +237,11 @@ TEH_TEST_handler_test_hkdf (struct TEH_RequestHandler *rh, NULL, 0)); GNUNET_JSON_parse_free (spec); json = GNUNET_JSON_from_data_auto (&hc); - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:o}", - "output", - json); + return TALER_MHD_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:o}", + "output", + json); } @@ -277,18 +277,18 @@ TEH_TEST_handler_test_ecdhe (struct TEH_RequestHandler *rh, GNUNET_JSON_spec_end () }; - res = TEH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &json); + res = TALER_MHD_parse_post_json (connection, + connection_cls, + upload_data, + upload_data_size, + &json); if (GNUNET_SYSERR == res) return MHD_NO; if ( (GNUNET_NO == res) || (NULL == json) ) return MHD_YES; - res = TEH_PARSE_json_data (connection, - json, - spec); + res = TALER_MHD_parse_json_data (connection, + json, + spec); json_decref (json); if (GNUNET_YES != res) return (GNUNET_NO == res) ? MHD_YES : MHD_NO; @@ -298,16 +298,17 @@ TEH_TEST_handler_test_ecdhe (struct TEH_RequestHandler *rh, &hc)) { GNUNET_JSON_parse_free (spec); - return TEH_RESPONSE_reply_internal_error (connection, - TALER_EC_TEST_ECDH_ERROR, - "Failed to perform ECDH"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_TEST_ECDH_ERROR, + "Failed to perform ECDH"); } GNUNET_JSON_parse_free (spec); - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:o}", - "ecdh_hash", - GNUNET_JSON_from_data_auto (&hc)); + return TALER_MHD_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:o}", + "ecdh_hash", + GNUNET_JSON_from_data_auto (&hc)); } @@ -345,18 +346,18 @@ TEH_TEST_handler_test_eddsa (struct TEH_RequestHandler *rh, }; struct GNUNET_CRYPTO_EddsaPrivateKey *pk; - res = TEH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &json); + res = TALER_MHD_parse_post_json (connection, + connection_cls, + upload_data, + upload_data_size, + &json); if (GNUNET_SYSERR == res) return MHD_NO; if ( (GNUNET_NO == res) || (NULL == json) ) return MHD_YES; - res = TEH_PARSE_json_data (connection, - json, - spec); + res = TALER_MHD_parse_json_data (connection, + json, + spec); json_decref (json); if (GNUNET_YES != res) return (GNUNET_NO == res) ? MHD_YES : MHD_NO; @@ -369,9 +370,10 @@ TEH_TEST_handler_test_eddsa (struct TEH_RequestHandler *rh, &pub)) { GNUNET_JSON_parse_free (spec); - return TEH_RESPONSE_reply_signature_invalid (connection, - TALER_EC_TEST_EDDSA_INVALID, - "eddsa_sig"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_FORBIDDEN, + TALER_EC_TEST_EDDSA_INVALID, + "eddsa_sig"); } GNUNET_JSON_parse_free (spec); pk = GNUNET_CRYPTO_eddsa_key_create (); @@ -382,20 +384,21 @@ TEH_TEST_handler_test_eddsa (struct TEH_RequestHandler *rh, &sig)) { GNUNET_free (pk); - return TEH_RESPONSE_reply_internal_error (connection, - TALER_EC_TEST_EDDSA_ERROR, - "Failed to EdDSA-sign"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_TEST_EDDSA_ERROR, + "Failed to EdDSA-sign"); } GNUNET_CRYPTO_eddsa_key_get_public (pk, &pub); GNUNET_free (pk); - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:o, s:o}", - "eddsa_pub", - GNUNET_JSON_from_data_auto (&pub), - "eddsa_sig", - GNUNET_JSON_from_data_auto (&sig)); + return TALER_MHD_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:o, s:o}", + "eddsa_pub", + GNUNET_JSON_from_data_auto (&pub), + "eddsa_sig", + GNUNET_JSON_from_data_auto (&sig)); } @@ -425,23 +428,25 @@ TEH_TEST_handler_test_rsa_get (struct TEH_RequestHandler *rh, if (NULL == rsa_pk) { GNUNET_break (0); - return TEH_RESPONSE_reply_internal_error (connection, - TALER_EC_TEST_RSA_GEN_ERROR, - "Failed to create RSA key"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_TEST_RSA_GEN_ERROR, + "Failed to create RSA key"); } pub = GNUNET_CRYPTO_rsa_private_key_get_public (rsa_pk); if (NULL == pub) { GNUNET_break (0); - return TEH_RESPONSE_reply_internal_error (connection, - TALER_EC_TEST_RSA_PUB_ERROR, - "Failed to get public RSA key"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_TEST_RSA_PUB_ERROR, + "Failed to get public RSA key"); } - res = TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:o}", - "rsa_pub", - GNUNET_JSON_from_rsa_public_key (pub)); + res = TALER_MHD_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:o}", + "rsa_pub", + GNUNET_JSON_from_rsa_public_key (pub)); GNUNET_CRYPTO_rsa_public_key_free (pub); return res; } @@ -476,18 +481,18 @@ TEH_TEST_handler_test_rsa_sign (struct TEH_RequestHandler *rh, GNUNET_JSON_spec_end () }; - res = TEH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &json); + res = TALER_MHD_parse_post_json (connection, + connection_cls, + upload_data, + upload_data_size, + &json); if (GNUNET_SYSERR == res) return MHD_NO; if ( (GNUNET_NO == res) || (NULL == json) ) return MHD_YES; - res = TEH_PARSE_json_data (connection, - json, - spec); + res = TALER_MHD_parse_json_data (connection, + json, + spec); json_decref (json); if (GNUNET_YES != res) return (GNUNET_NO == res) ? MHD_YES : MHD_NO; @@ -497,9 +502,10 @@ TEH_TEST_handler_test_rsa_sign (struct TEH_RequestHandler *rh, { GNUNET_break (0); GNUNET_JSON_parse_free (spec); - return TEH_RESPONSE_reply_internal_error (connection, - TALER_EC_TEST_RSA_GEN_ERROR, - "Failed to create RSA key"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_TEST_RSA_GEN_ERROR, + "Failed to create RSA key"); } sig = GNUNET_CRYPTO_rsa_sign_blinded (rsa_pk, in_ptr, @@ -508,16 +514,17 @@ TEH_TEST_handler_test_rsa_sign (struct TEH_RequestHandler *rh, { GNUNET_break (0); GNUNET_JSON_parse_free (spec); - return TEH_RESPONSE_reply_internal_error (connection, - TALER_EC_TEST_RSA_SIGN_ERROR, - "Failed to RSA-sign"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_TEST_RSA_SIGN_ERROR, + "Failed to RSA-sign"); } GNUNET_JSON_parse_free (spec); - res = TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:o}", - "rsa_blind_sig", - GNUNET_JSON_from_rsa_signature (sig)); + res = TALER_MHD_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:o}", + "rsa_blind_sig", + GNUNET_JSON_from_rsa_signature (sig)); GNUNET_CRYPTO_rsa_signature_free (sig); return res; } @@ -555,29 +562,29 @@ TEH_TEST_handler_test_transfer (struct TEH_RequestHandler *rh, }; struct TALER_TransferSecretP secret; - res = TEH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &json); + res = TALER_MHD_parse_post_json (connection, + connection_cls, + upload_data, + upload_data_size, + &json); if (GNUNET_SYSERR == res) return MHD_NO; if ( (GNUNET_NO == res) || (NULL == json) ) return MHD_YES; - res = TEH_PARSE_json_data (connection, - json, - spec); + res = TALER_MHD_parse_json_data (connection, + json, + spec); json_decref (json); if (GNUNET_YES != res) return (GNUNET_NO == res) ? MHD_YES : MHD_NO; TALER_link_reveal_transfer_secret (&trans_priv, &coin_pub, &secret); - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:o}", - "secret", - GNUNET_JSON_from_data_auto (&secret)); + return TALER_MHD_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:o}", + "secret", + GNUNET_JSON_from_data_auto (&secret)); } @@ -601,11 +608,11 @@ TEH_TEST_handler_test (struct TEH_RequestHandler *rh, json_t *json; int res; - res = TEH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &json); + res = TALER_MHD_parse_post_json (connection, + connection_cls, + upload_data, + upload_data_size, + &json); if (GNUNET_SYSERR == res) return MHD_NO; if ( (GNUNET_NO == res) || (NULL == json) ) diff --git a/src/exchange/taler-exchange-httpd_track_transaction.c b/src/exchange/taler-exchange-httpd_track_transaction.c index 3b8d14a01..757f28bad 100644 --- a/src/exchange/taler-exchange-httpd_track_transaction.c +++ b/src/exchange/taler-exchange-httpd_track_transaction.c @@ -23,8 +23,9 @@ #include <jansson.h> #include <microhttpd.h> #include <pthread.h> +#include "taler_json_lib.h" +#include "taler_mhd_lib.h" #include "taler_signatures.h" -#include "taler-exchange-httpd_parsing.h" #include "taler-exchange-httpd_keystate.h" #include "taler-exchange-httpd_track_transaction.h" #include "taler-exchange-httpd_responses.h" @@ -42,12 +43,12 @@ static int reply_transfer_pending (struct MHD_Connection *connection, struct GNUNET_TIME_Absolute planned_exec_time) { - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_ACCEPTED, - "{s:o}", - "execution_time", - GNUNET_JSON_from_time_abs ( - planned_exec_time)); + return TALER_MHD_reply_json_pack (connection, + MHD_HTTP_ACCEPTED, + "{s:o}", + "execution_time", + GNUNET_JSON_from_time_abs ( + planned_exec_time)); } @@ -92,24 +93,25 @@ reply_track_transaction (struct MHD_Connection *connection, &pub, &sig)) { - return TEH_RESPONSE_reply_internal_error (connection, - TALER_EC_EXCHANGE_BAD_CONFIGURATION, - "no keys"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_EXCHANGE_BAD_CONFIGURATION, + "no keys"); } - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:o, s:o, s:o, s:o, s:o}", - "wtid", GNUNET_JSON_from_data_auto ( - wtid), - "execution_time", - GNUNET_JSON_from_time_abs (exec_time), - "coin_contribution", - TALER_JSON_from_amount ( - coin_contribution), - "exchange_sig", - GNUNET_JSON_from_data_auto (&sig), - "exchange_pub", - GNUNET_JSON_from_data_auto (&pub)); + return TALER_MHD_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:o, s:o, s:o, s:o, s:o}", + "wtid", GNUNET_JSON_from_data_auto ( + wtid), + "execution_time", + GNUNET_JSON_from_time_abs (exec_time), + "coin_contribution", + TALER_JSON_from_amount ( + coin_contribution), + "exchange_sig", + GNUNET_JSON_from_data_auto (&sig), + "exchange_pub", + GNUNET_JSON_from_data_auto (&pub)); } @@ -249,15 +251,19 @@ track_transaction_transaction (void *cls, if (GNUNET_DB_STATUS_HARD_ERROR == qs) { GNUNET_break (0); - *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_TRACK_TRANSACTION_DB_FETCH_FAILED); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_TRACK_TRANSACTION_DB_FETCH_FAILED, + "failed to fetch transaction data"); } return qs; } if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) { - *mhd_ret = TEH_RESPONSE_reply_transaction_unknown (connection, - TALER_EC_TRACK_TRANSACTION_NOT_FOUND); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_TRACK_TRANSACTION_NOT_FOUND, + "transaction unknown"); return GNUNET_DB_STATUS_HARD_ERROR; } return qs; @@ -295,9 +301,10 @@ check_and_handle_track_transaction_request (struct MHD_Connection *connection, &merchant_pub->eddsa_pub)) { GNUNET_break_op (0); - return TEH_RESPONSE_reply_signature_invalid (connection, - TALER_EC_TRACK_TRANSACTION_MERCHANT_SIGNATURE_INVALID, - "merchant_sig"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_FORBIDDEN, + TALER_EC_TRACK_TRANSACTION_MERCHANT_SIGNATURE_INVALID, + "merchant_sig"); } ctx.pending = GNUNET_NO; ctx.tps = tps; @@ -314,8 +321,10 @@ check_and_handle_track_transaction_request (struct MHD_Connection *connection, return reply_transfer_pending (connection, ctx.execution_time); if (GNUNET_SYSERR == ctx.pending) - return TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_TRACK_TRANSACTION_DB_FEE_INCONSISTENT); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_TRACK_TRANSACTION_DB_FEE_INCONSISTENT, + "fees are inconsistent"); return reply_track_transaction (connection, &tps->h_contract_terms, &tps->h_wire, @@ -357,18 +366,18 @@ TEH_TRACKING_handler_track_transaction (struct TEH_RequestHandler *rh, }; (void) rh; - res = TEH_PARSE_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &json); + res = TALER_MHD_parse_post_json (connection, + connection_cls, + upload_data, + upload_data_size, + &json); if (GNUNET_SYSERR == res) return MHD_NO; if ( (GNUNET_NO == res) || (NULL == json) ) return MHD_YES; - res = TEH_PARSE_json_data (connection, - json, - spec); + res = TALER_MHD_parse_json_data (connection, + json, + spec); if (GNUNET_OK != res) { json_decref (json); diff --git a/src/exchange/taler-exchange-httpd_track_transfer.c b/src/exchange/taler-exchange-httpd_track_transfer.c index cacbfaa85..f40d7c819 100644 --- a/src/exchange/taler-exchange-httpd_track_transfer.c +++ b/src/exchange/taler-exchange-httpd_track_transfer.c @@ -24,10 +24,11 @@ #include <microhttpd.h> #include <pthread.h> #include "taler_signatures.h" -#include "taler-exchange-httpd_parsing.h" #include "taler-exchange-httpd_keystate.h" #include "taler-exchange-httpd_track_transfer.h" #include "taler-exchange-httpd_responses.h" +#include "taler_json_lib.h" +#include "taler_mhd_lib.h" #include "taler_wire_lib.h" @@ -148,29 +149,30 @@ reply_track_transfer_details (struct MHD_Connection *connection, &sig)) { json_decref (deposits); - return TEH_RESPONSE_reply_internal_error (connection, - TALER_EC_EXCHANGE_BAD_CONFIGURATION, - "no keys"); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_EXCHANGE_BAD_CONFIGURATION, + "no keys"); } - return TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_OK, - "{s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o}", - "total", TALER_JSON_from_amount (total), - "wire_fee", TALER_JSON_from_amount ( - wire_fee), - "merchant_pub", - GNUNET_JSON_from_data_auto ( - merchant_pub), - "H_wire", GNUNET_JSON_from_data_auto ( - h_wire), - "execution_time", - GNUNET_JSON_from_time_abs (exec_time), - "deposits", deposits, - "exchange_sig", - GNUNET_JSON_from_data_auto (&sig), - "exchange_pub", - GNUNET_JSON_from_data_auto (&pub)); + return TALER_MHD_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o}", + "total", TALER_JSON_from_amount (total), + "wire_fee", TALER_JSON_from_amount ( + wire_fee), + "merchant_pub", + GNUNET_JSON_from_data_auto ( + merchant_pub), + "H_wire", GNUNET_JSON_from_data_auto ( + h_wire), + "execution_time", + GNUNET_JSON_from_time_abs (exec_time), + "deposits", deposits, + "exchange_sig", + GNUNET_JSON_from_data_auto (&sig), + "exchange_pub", + GNUNET_JSON_from_data_auto (&pub)); } @@ -396,23 +398,28 @@ track_transfer_transaction (void *cls, if (GNUNET_DB_STATUS_HARD_ERROR == qs) { GNUNET_break (0); - *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_TRACK_TRANSFER_DB_FETCH_FAILED); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_TRACK_TRANSFER_DB_FETCH_FAILED, + "failed to fetch transaction data"); } return qs; } if (GNUNET_SYSERR == ctx->is_valid) { GNUNET_break (0); - *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_TRACK_TRANSFER_DB_INCONSISTENT); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_TRACK_TRANSFER_DB_INCONSISTENT, + "exchange database internally inconsistent"); return GNUNET_DB_STATUS_HARD_ERROR; } if (GNUNET_NO == ctx->is_valid) { - *mhd_ret = TEH_RESPONSE_reply_arg_unknown (connection, - TALER_EC_TRACK_TRANSFER_WTID_NOT_FOUND, - "wtid"); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_TRACK_TRANSFER_WTID_NOT_FOUND, + "wtid"); return GNUNET_DB_STATUS_HARD_ERROR; } qs = TEH_plugin->get_wire_fee (TEH_plugin->cls, @@ -430,8 +437,10 @@ track_transfer_transaction (void *cls, (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS) ) { GNUNET_break (0); - *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_TRACK_TRANSFER_WIRE_FEE_NOT_FOUND); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_TRACK_TRANSFER_WIRE_FEE_NOT_FOUND, + "did not find wire fee"); } return qs; } @@ -441,8 +450,10 @@ track_transfer_transaction (void *cls, &ctx->wire_fee)) { GNUNET_break (0); - *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection, - TALER_EC_TRACK_TRANSFER_WIRE_FEE_INCONSISTENT); + *mhd_ret = TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_TRACK_TRANSFER_WIRE_FEE_INCONSISTENT, + "could not subtract wire fee"); return GNUNET_DB_STATUS_HARD_ERROR; } return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; @@ -492,11 +503,11 @@ TEH_TRACKING_handler_track_transfer (struct TEH_RequestHandler *rh, int mhd_ret; memset (&ctx, 0, sizeof (ctx)); - res = TEH_PARSE_mhd_request_arg_data (connection, - "wtid", - &ctx.wtid, - sizeof (struct - TALER_WireTransferIdentifierRawP)); + res = TALER_MHD_parse_request_arg_data (connection, + "wtid", + &ctx.wtid, + sizeof (struct + TALER_WireTransferIdentifierRawP)); if (GNUNET_SYSERR == res) return MHD_NO; /* internal error */ if (GNUNET_NO == res) diff --git a/src/exchange/taler-exchange-httpd_wire.c b/src/exchange/taler-exchange-httpd_wire.c index 91c928f94..4e4c34db5 100644 --- a/src/exchange/taler-exchange-httpd_wire.c +++ b/src/exchange/taler-exchange-httpd_wire.c @@ -25,6 +25,7 @@ #include "taler-exchange-httpd_validation.h" #include "taler-exchange-httpd_wire.h" #include "taler_json_lib.h" +#include "taler_mhd_lib.h" #include <jansson.h> /** @@ -140,9 +141,9 @@ TEH_WIRE_handler_wire (struct TEH_RequestHandler *rh, (void) upload_data; (void) upload_data_size; GNUNET_assert (NULL != wire_methods); - return TEH_RESPONSE_reply_json (connection, - wire_methods, - MHD_HTTP_OK); + return TALER_MHD_reply_json (connection, + wire_methods, + MHD_HTTP_OK); } diff --git a/src/exchange/taler-exchange-wirewatch.c b/src/exchange/taler-exchange-wirewatch.c index 3699c9d3b..21f62cd82 100644 --- a/src/exchange/taler-exchange-wirewatch.c +++ b/src/exchange/taler-exchange-wirewatch.c @@ -733,10 +733,10 @@ main (int argc, options, &run, NULL)) { - GNUNET_free ((void*) argv); + GNUNET_free ((void *) argv); return 1; } - GNUNET_free ((void*) argv); + GNUNET_free ((void *) argv); return global_ret; } diff --git a/src/include/Makefile.am b/src/include/Makefile.am index 1e624caa4..645bdc9f9 100644 --- a/src/include/Makefile.am +++ b/src/include/Makefile.am @@ -27,6 +27,7 @@ talerinclude_HEADERS = \ taler_json_lib.h \ taler_testing_lib.h \ taler_util.h \ + taler_mhd_lib.h \ taler_pq_lib.h \ taler_signatures.h \ taler_wire_lib.h \ diff --git a/src/include/gauger.h b/src/include/gauger.h index 7d66051b7..36dc055bb 100644 --- a/src/include/gauger.h +++ b/src/include/gauger.h @@ -35,7 +35,7 @@ __gauger_v[7] = "-c"; \ __gauger_v[8] = (char *) category; \ __gauger_v[9] = (char *) NULL; \ - execvp ("gauger", (char*const*) __gauger_v); \ + execvp ("gauger", (char *const *) __gauger_v); \ perror ("gauger"); \ _exit (1); \ }else{ \ diff --git a/src/include/taler_error_codes.h b/src/include/taler_error_codes.h index 917f3fc93..9986c9d10 100644 --- a/src/include/taler_error_codes.h +++ b/src/include/taler_error_codes.h @@ -188,7 +188,7 @@ enum TALER_ErrorCode * requested withdraw operation at this time. The response includes * the current "balance" of the reserve as well as the transaction * "history" that lead to this balance. This response is provided - * with HTTP status code MHD_HTTP_FORBIDDEN. + * with HTTP status code MHD_HTTP_CONFLICT. */ TALER_EC_WITHDRAW_INSUFFICIENT_FUNDS = 1100, @@ -340,7 +340,7 @@ enum TALER_ErrorCode * for the /deposit operation (i.e. due to double spending). * The "history" in the respose provides the transaction history * of the coin proving this fact. This response is provided - * with HTTP status code MHD_HTTP_FORBIDDEN. + * with HTTP status code MHD_HTTP_CONFLICT. */ TALER_EC_DEPOSIT_INSUFFICIENT_FUNDS = 1200, @@ -496,7 +496,7 @@ enum TALER_ErrorCode * for the /refresh/melt operation. The "history" in this * response provdes the "residual_value" of the coin, which may * be less than its "original_value". This response is provided - * with HTTP status code MHD_HTTP_FORBIDDEN. + * with HTTP status code MHD_HTTP_CONFLICT. */ TALER_EC_REFRESH_MELT_INSUFFICIENT_FUNDS = 1300, @@ -929,7 +929,7 @@ enum TALER_ErrorCode /** * The given coin signature is invalid for the request. * This response is provided with an - * HTTP status code of MHD_HTTP_UNAUTHORIZED. + * HTTP status code of MHD_HTTP_FORBIDDEN. */ TALER_EC_PAYBACK_SIGNATURE_INVALID = 1851, @@ -1442,6 +1442,7 @@ enum TALER_ErrorCode * The amount to be refunded is inconsistent: either is lower than * the previous amount being awarded, or it is too big to be paid back. * In this second case, the fault stays on the business dept. side. + * Returned with an HTTP status of #MHD_HTTP_CONFLICT. */ TALER_EC_REFUND_INCONSISTENT_AMOUNT = 2602, @@ -1851,7 +1852,7 @@ enum TALER_ErrorCode /** * The sync service failed to access its database. * This response is provided with HTTP status code - * MHD_HTTP_INTERNAL_ERROR. + * MHD_HTTP_INTERNAL_SERVER_ERROR. */ TALER_EC_SYNC_DB_FETCH_ERROR = 6000, @@ -1905,7 +1906,7 @@ enum TALER_ErrorCode * The signature provided in the "Sync-Signature" header * does not match the account, old or new Etags. * This response is provided with HTTP status code - * MHD_HTTP_UNAUTHORIZED. + * MHD_HTTP_FORBIDDEN. */ TALER_EC_SYNC_INVALID_SIGNATURE = 6007, @@ -1985,7 +1986,6 @@ enum TALER_ErrorCode */ TALER_EC_SYNC_PAYMENT_CHECK_ORDER_DB_ERROR = 6017, - /** * End of error code range. */ diff --git a/src/include/taler_json_lib.h b/src/include/taler_json_lib.h index 382bb19ee..6adb76b24 100644 --- a/src/include/taler_json_lib.h +++ b/src/include/taler_json_lib.h @@ -126,6 +126,19 @@ enum TALER_ErrorCode TALER_JSON_get_error_code (const json_t *json); +/** + * Extract the Taler error code from the given @a data object, which is expected to be in JSON. + * Note that #TALER_EC_INVALID is returned if no "code" is present or if @a data is not in JSON. + * + * @param data response to extract the error code from + * @param data_size number of bytes in @a data + * @return the "code" value from @a json + */ +enum TALER_ErrorCode +TALER_JSON_get_error_code2 (const void *data, + size_t data_size); + + /* **************** /wire account offline signing **************** */ /** diff --git a/src/include/taler_mhd_lib.h b/src/include/taler_mhd_lib.h new file mode 100644 index 000000000..cdbc8d290 --- /dev/null +++ b/src/include/taler_mhd_lib.h @@ -0,0 +1,393 @@ +/* + This file is part of TALER + Copyright (C) 2014 GNUnet e.V. + + 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 + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file taler_mhd_lib.h + * @brief API for generating MHD replies + * @author Florian Dold + * @author Benedikt Mueller + * @author Christian Grothoff + */ +#ifndef TALER_MHD_LIB_H +#define TALER_MHD_LIB_H +#include <gnunet/gnunet_util_lib.h> +#include <gnunet/gnunet_json_lib.h> +#include <jansson.h> +#include <microhttpd.h> +#include "taler_error_codes.h" + +/** + * Global options for response generation. + */ +enum TALER_MHD_GlobalOptions +{ + + /** + * Use defaults. + */ + TALER_MHD_GO_NONE = 0, + + /** + * Add "Connection: Close" header. + */ + TALER_MHD_GO_FORCE_CONNECTION_CLOSE = 1, + + /** + * Disable use of compression, even if the client + * supports it. + */ + TALER_MHD_GO_DISABLE_COMPRESSION = 2 + +}; + + +/** + * Set global options for response generation + * within libtalermhd. + * + * @param go global options to use + */ +void +TALER_MHD_setup (enum TALER_MHD_GlobalOptions go); + + +/** + * Add headers we want to return in every response. + * Useful for testing, like if we want to always close + * connections. + * + * @param response response to modify + */ +void +TALER_MHD_add_global_headers (struct MHD_Response *response); + + +/** + * Try to compress a response body. Updates @a buf and @a buf_size. + * + * @param[in,out] buf pointer to body to compress + * @param[in,out] buf_size pointer to initial size of @a buf + * @return #MHD_YES if @a buf was compressed + */ +int +TALER_MHD_body_compress (void **buf, + size_t *buf_size); + + +/** + * Is HTTP body deflate compression supported by the client? + * + * @param connection connection to check + * @return #MHD_YES if 'deflate' compression is allowed + */ +int +TALER_MHD_can_compress (struct MHD_Connection *connection); + + +/** + * Send JSON object as response. + * + * @param connection the MHD connection + * @param json the json object + * @param response_code the http response code + * @return MHD result code + */ +int +TALER_MHD_reply_json (struct MHD_Connection *connection, + const json_t *json, + unsigned int response_code); + + +/** + * Function to call to handle the request by building a JSON + * reply from a format string and varargs. + * + * @param connection the MHD connection to handle + * @param response_code HTTP response code to use + * @param fmt format string for pack + * @param ... varargs + * @return MHD result code + */ +int +TALER_MHD_reply_json_pack (struct MHD_Connection *connection, + unsigned int response_code, + const char *fmt, + ...); + + +/** + * Send a response indicating an error. + * + * @param connection the MHD connection to use + * @param ec error code uniquely identifying the error + * @param http_status HTTP status code to use + * @param hint human readable hint about the error + * @return a MHD result code + */ +int +TALER_MHD_reply_with_error (struct MHD_Connection *connection, + unsigned int http_status, + enum TALER_ErrorCode ec, + const char *hint); + + +/** + * Make JSON response object. + * + * @param json the json object + * @return MHD response object + */ +struct MHD_Response * +TALER_MHD_make_json (const json_t *json); + + +/** + * Make JSON response object. + * + * @param fmt format string for pack + * @param ... varargs + * @return MHD response object + */ +struct MHD_Response * +TALER_MHD_make_json_pack (const char *fmt, + ...); + + +/** + * Create a response indicating an internal error. + * + * @param ec error code to return + * @param hint hint about the internal error's nature + * @return a MHD response object + */ +struct MHD_Response * +TALER_MHD_make_error (enum TALER_ErrorCode ec, + const char *hint); + + +/** + * Send a response indicating that the request was too big. + * + * @param connection the MHD connection to use + * @return a MHD result code + */ +int +TALER_MHD_reply_request_too_large (struct MHD_Connection *connection); + + +/** + * Function to call to handle the request by sending + * back a redirect to the AGPL source code. + * + * @param connection the MHD connection to handle + * @param url where to redirect for the sources + * @return MHD result code + */ +int +TALER_MHD_reply_agpl (struct MHD_Connection *connection, + const char *url); + + +/** + * Function to call to handle the request by sending + * back static data. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param http_status status code to return + * @param mime_type content-type to use + * @param body response payload + * @param body_size number of bytes in @a body + * @return MHD result code + */ +int +TALER_MHD_reply_static (struct MHD_Connection *connection, + unsigned int http_status, + const char *mime_type, + const char *body, + size_t body_size); + + +/** + * Process a POST request containing a JSON object. This + * function realizes an MHD POST processor that will + * (incrementally) process JSON data uploaded to the HTTP + * server. It will store the required state in the + * "connection_cls", which must be cleaned up using + * #TALER_MHD_post_cleanup_callback(). + * + * @param connection the MHD connection + * @param con_cls the closure (points to a `struct Buffer *`) + * @param upload_data the POST data + * @param upload_data_size number of bytes in @a upload_data + * @param json the JSON object for a completed request + * @return + * #GNUNET_YES if json object was parsed or at least + * may be parsed in the future (call again); + * `*json` will be NULL if we need to be called again, + * and non-NULL if we are done. + * #GNUNET_NO is request incomplete or invalid + * (error message was generated) + * #GNUNET_SYSERR on internal error + * (we could not even queue an error message, + * close HTTP session with MHD_NO) + */ +int +TALER_MHD_parse_post_json (struct MHD_Connection *connection, + void **con_cls, + const char *upload_data, + size_t *upload_data_size, + json_t **json); + + +/** + * Function called whenever we are done with a request + * to clean up our state. + * + * @param con_cls value as it was left by + * #TALER_MHD_post_json(), to be cleaned up + */ +void +TALER_MHD_parse_post_cleanup_callback (void *con_cls); + + +/** + * Parse JSON object into components based on the given field + * specification. + * + * @param connection the connection to send an error response to + * @param root the JSON node to start the navigation at. + * @param spec field specification for the parser + * @return + * #GNUNET_YES if navigation was successful (caller is responsible + * for freeing allocated variable-size data using + * GNUNET_JSON_parse_free() when done) + * #GNUNET_NO if json is malformed, error response was generated + * #GNUNET_SYSERR on internal error + */ +int +TALER_MHD_parse_json_data (struct MHD_Connection *connection, + const json_t *root, + struct GNUNET_JSON_Specification *spec); + + +/** + * Parse JSON array into components based on the given field + * specification. Generates error response on parse errors. + * + * @param connection the connection to send an error response to + * @param root the JSON node to start the navigation at. + * @param[in,out] spec field specification for the parser + * @param ... -1-terminated list of array offsets of type 'int' + * @return + * #GNUNET_YES if navigation was successful (caller is responsible + * for freeing allocated variable-size data using + * GNUNET_JSON_parse_free() when done) + * #GNUNET_NO if json is malformed, error response was generated + * #GNUNET_SYSERR on internal error + */ +int +TALER_MHD_parse_json_array (struct MHD_Connection *connection, + const json_t *root, + struct GNUNET_JSON_Specification *spec, + ...); + + +/** + * Extraxt fixed-size base32crockford encoded data from request. + * + * Queues an error response to the connection if the parameter is missing or + * invalid. + * + * @param connection the MHD connection + * @param param_name the name of the parameter with the key + * @param[out] out_data pointer to store the result + * @param out_size expected size of @a out_data + * @return + * #GNUNET_YES if the the argument is present + * #GNUNET_NO if the argument is absent or malformed + * #GNUNET_SYSERR on internal error (error response could not be sent) + */ +int +TALER_MHD_parse_request_arg_data (struct MHD_Connection *connection, + const char *param_name, + void *out_data, + size_t out_size); + + +/** + * Parse the configuration to determine on which port + * or UNIX domain path we should run an HTTP service. + * + * @param cfg configuration to parse + * @param section section of the configuration to parse (usually "exchange") + * @param[out] rport set to the port number, or 0 for none + * @param[out] unix_path set to the UNIX path, or NULL for none + * @param[out] unix_mode set to the mode to be used for @a unix_path + * @return #GNUNET_OK on success + */ +int +TALER_MHD_parse_config (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *section, + uint16_t *rport, + char **unix_path, + mode_t *unix_mode); + + +/** + * Function called for logging by MHD. + * + * @param cls closure, NULL + * @param fm format string (`printf()`-style) + * @param ap arguments to @a fm + */ +void +TALER_MHD_handle_logs (void *cls, + const char *fm, + va_list ap); + + +/** + * Open UNIX domain socket for listining at @a unix_path with + * permissions @a unix_mode. + * + * @param unix_path where to listen + * @param unix_mode access permissions to set + * @return -1 on error, otherwise the listen socket + */ +int +TALER_MHD_open_unix_path (const char *unix_path, + mode_t unix_mode); + + +/** + * Bind a listen socket to the UNIX domain path + * or the TCP port and IP address as specified + * in @a cfg in section @a section. IF only a + * port was specified, set @a port and return -1. + * Otherwise, return the bound file descriptor. + * + * @param cfg configuration to parse + * @param section configuration section to use + * @param port[out] port to set, if TCP without BINDTO + * @return -1 and a port of zero on error, otherwise + * either -1 and a port, or a bound stream socket + */ +int +TALER_MHD_bind (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *section, + uint16_t *port); + +#endif diff --git a/src/json/json.c b/src/json/json.c index 90fe3dd4f..8d4089795 100644 --- a/src/json/json.c +++ b/src/json/json.c @@ -80,4 +80,33 @@ TALER_JSON_get_error_code (const json_t *json) } +/** + * Extract the Taler error code from the given @a data object, which is expected to be in JSON. + * Note that #TALER_EC_INVALID is returned if no "code" is present or if @a data is not in JSON. + * + * @param data response to extract the error code from + * @param data_size number of bytes in @a data + * @return the "code" value from @a json + */ +enum TALER_ErrorCode +TALER_JSON_get_error_code2 (const void *data, + size_t data_size) +{ + json_t *json; + enum TALER_ErrorCode ec; + json_error_t err; + + json = json_loads (data, + data_size, + &err); + if (NULL == json) + return TALER_EC_INVALID; + ec = TALER_JSON_get_error_code (json); + json_decref (json); + if (ec == TALER_EC_NONE) + return TALER_EC_INVALID; + return ec; +} + + /* End of json/json.c */ diff --git a/src/lib/auditor_api_deposit_confirmation.c b/src/lib/auditor_api_deposit_confirmation.c index f221b7fd7..73173cc31 100644 --- a/src/lib/auditor_api_deposit_confirmation.c +++ b/src/lib/auditor_api_deposit_confirmation.c @@ -99,7 +99,7 @@ handle_deposit_confirmation_finished (void *cls, /* 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_UNAUTHORIZED: + case MHD_HTTP_FORBIDDEN: /* 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 */ diff --git a/src/lib/exchange_api_curl_defaults.c b/src/lib/exchange_api_curl_defaults.c index 36d1edf7b..7b642bc89 100644 --- a/src/lib/exchange_api_curl_defaults.c +++ b/src/lib/exchange_api_curl_defaults.c @@ -35,7 +35,6 @@ TEL_curl_easy_get (const char *url) CURL *eh; eh = curl_easy_init (); - GNUNET_assert (CURLE_OK == curl_easy_setopt (eh, CURLOPT_URL, diff --git a/src/lib/exchange_api_deposit.c b/src/lib/exchange_api_deposit.c index 48f9a06bb..30bb6c976 100644 --- a/src/lib/exchange_api_deposit.c +++ b/src/lib/exchange_api_deposit.c @@ -325,7 +325,7 @@ handle_deposit_finished (void *cls, /* 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_FORBIDDEN: + case MHD_HTTP_CONFLICT: /* Double spending; check signatures on transaction history */ if (GNUNET_OK != verify_deposit_signature_forbidden (dh, @@ -335,7 +335,7 @@ handle_deposit_finished (void *cls, response_code = 0; } break; - case MHD_HTTP_UNAUTHORIZED: + case MHD_HTTP_FORBIDDEN: /* Nothing really to verify, exchange says one of the signatures is invalid; as we checked them, this should never happen, we should pass the JSON reply to the application */ diff --git a/src/lib/exchange_api_payback.c b/src/lib/exchange_api_payback.c index 912548cfe..f9df27e7a 100644 --- a/src/lib/exchange_api_payback.c +++ b/src/lib/exchange_api_payback.c @@ -226,7 +226,7 @@ handle_payback_finished (void *cls, /* 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_FORBIDDEN: + case MHD_HTTP_CONFLICT: { /* Insufficient funds, proof attached */ json_t *history; @@ -256,7 +256,7 @@ handle_payback_finished (void *cls, TALER_EXCHANGE_payback_cancel (ph); return; } - case MHD_HTTP_UNAUTHORIZED: + case MHD_HTTP_FORBIDDEN: /* Nothing really to verify, exchange says one of the signatures is invalid; as we checked them, this should never happen, we should pass the JSON reply to the application */ diff --git a/src/lib/exchange_api_refresh.c b/src/lib/exchange_api_refresh.c index db3692bcd..a75baec86 100644 --- a/src/lib/exchange_api_refresh.c +++ b/src/lib/exchange_api_refresh.c @@ -939,7 +939,7 @@ verify_refresh_melt_signature_ok (struct TALER_EXCHANGE_RefreshMeltHandle *rmh, /** - * Verify that the signatures on the "403 FORBIDDEN" response from the + * Verify that the signatures on the "409 CONFLICT" response from the * exchange demonstrating customer double-spending are valid. * * @param rmh melt handle @@ -947,9 +947,9 @@ verify_refresh_melt_signature_ok (struct TALER_EXCHANGE_RefreshMeltHandle *rmh, * @return #GNUNET_OK if the signature(s) is valid, #GNUNET_SYSERR if not */ static int -verify_refresh_melt_signature_forbidden (struct - TALER_EXCHANGE_RefreshMeltHandle *rmh, - const json_t *json) +verify_refresh_melt_signature_conflict (struct + TALER_EXCHANGE_RefreshMeltHandle *rmh, + const json_t *json) { json_t *history; struct TALER_Amount original_value; @@ -1083,17 +1083,17 @@ handle_refresh_melt_finished (void *cls, /* 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_FORBIDDEN: + case MHD_HTTP_CONFLICT: /* Double spending; check signatures on transaction history */ if (GNUNET_OK != - verify_refresh_melt_signature_forbidden (rmh, - j)) + verify_refresh_melt_signature_conflict (rmh, + j)) { GNUNET_break_op (0); response_code = 0; } break; - case MHD_HTTP_UNAUTHORIZED: + case MHD_HTTP_FORBIDDEN: /* Nothing really to verify, exchange says one of the signatures is invalid; assuming we checked them, this should never happen, we should pass the JSON reply to the application */ diff --git a/src/lib/exchange_api_refund.c b/src/lib/exchange_api_refund.c index e8ae6b74a..b8c422e88 100644 --- a/src/lib/exchange_api_refund.c +++ b/src/lib/exchange_api_refund.c @@ -169,7 +169,7 @@ handle_refund_finished (void *cls, /* 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_UNAUTHORIZED: + case MHD_HTTP_FORBIDDEN: /* Nothing really to verify, exchange says one of the signatures is invalid; as we checked them, this should never happen, we should pass the JSON reply to the application */ diff --git a/src/lib/exchange_api_reserve.c b/src/lib/exchange_api_reserve.c index a57d4e9dc..2c62cac20 100644 --- a/src/lib/exchange_api_reserve.c +++ b/src/lib/exchange_api_reserve.c @@ -797,7 +797,7 @@ reserve_withdraw_ok (struct TALER_EXCHANGE_ReserveWithdrawHandle *wsh, /** - * We got a 403 FORBIDDEN response for the /reserve/withdraw operation. + * We got a 409 CONFLICT response for the /reserve/withdraw operation. * Check the signatures on the withdraw transactions in the provided * history and that the balances add up. We don't do anything directly * with the information, as the JSON will be returned to the application. @@ -941,7 +941,7 @@ handle_reserve_withdraw_finished (void *cls, /* 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_FORBIDDEN: + case MHD_HTTP_CONFLICT: /* The exchange says that the reserve has insufficient funds; check the signatures in the history... */ if (GNUNET_OK != @@ -952,7 +952,7 @@ handle_reserve_withdraw_finished (void *cls, response_code = 0; } break; - case MHD_HTTP_UNAUTHORIZED: + case MHD_HTTP_FORBIDDEN: GNUNET_break (0); /* Nothing really to verify, exchange says one of the signatures is invalid; as we checked them, this should never happen, we diff --git a/src/lib/exchange_api_track_transaction.c b/src/lib/exchange_api_track_transaction.c index 29b85facf..de3f98b65 100644 --- a/src/lib/exchange_api_track_transaction.c +++ b/src/lib/exchange_api_track_transaction.c @@ -217,7 +217,7 @@ handle_deposit_wtid_finished (void *cls, /* 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_UNAUTHORIZED: + case MHD_HTTP_FORBIDDEN: /* Nothing really to verify, exchange says one of the signatures is invalid; as we checked them, this should never happen, we should pass the JSON reply to the application */ diff --git a/src/lib/exchange_api_track_transfer.c b/src/lib/exchange_api_track_transfer.c index 419998a2c..2c90bf199 100644 --- a/src/lib/exchange_api_track_transfer.c +++ b/src/lib/exchange_api_track_transfer.c @@ -279,7 +279,7 @@ handle_track_transfer_finished (void *cls, /* 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_UNAUTHORIZED: + case MHD_HTTP_FORBIDDEN: /* Nothing really to verify, exchange says one of the signatures is invalid; as we checked them, this should never happen, we should pass the JSON reply to the application */ diff --git a/src/lib/test_auditor_api.conf b/src/lib/test_auditor_api.conf index e01cbfcbd..3a12b3c5e 100644 --- a/src/lib/test_auditor_api.conf +++ b/src/lib/test_auditor_api.conf @@ -15,6 +15,8 @@ BASE_URL = "http://localhost:8083/" # HTTP port the auditor listens to PORT = 8083 +TINY_AMOUNT = EUR:0.01 + [exchange] # how long is one signkey valid? diff --git a/src/lib/test_exchange_api.c b/src/lib/test_exchange_api.c index 23a52be1f..4e8eb7e09 100644 --- a/src/lib/test_exchange_api.c +++ b/src/lib/test_exchange_api.c @@ -228,7 +228,7 @@ run (void *cls, TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-2", "create-reserve-1", "EUR:5", - MHD_HTTP_FORBIDDEN), + MHD_HTTP_CONFLICT), /** * Try to double spend using different wire details. @@ -238,7 +238,7 @@ run (void *cls, TALER_TESTING_make_wire_details (43, fakebank_url), "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", - GNUNET_TIME_UNIT_ZERO, "EUR:5", MHD_HTTP_FORBIDDEN), + GNUNET_TIME_UNIT_ZERO, "EUR:5", MHD_HTTP_CONFLICT), /** * Try to double spend using a different transaction id. @@ -253,7 +253,7 @@ run (void *cls, TALER_TESTING_make_wire_details (43, fakebank_url), "{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}", - GNUNET_TIME_UNIT_ZERO, "EUR:5", MHD_HTTP_FORBIDDEN), + GNUNET_TIME_UNIT_ZERO, "EUR:5", MHD_HTTP_CONFLICT), /** * Try to double spend with different proposal. @@ -263,7 +263,7 @@ run (void *cls, TALER_TESTING_make_wire_details (43, fakebank_url), "{\"items\":[{\"name\":\"ice cream\",\"value\":2}]}", - GNUNET_TIME_UNIT_ZERO, "EUR:5", MHD_HTTP_FORBIDDEN), + GNUNET_TIME_UNIT_ZERO, "EUR:5", MHD_HTTP_CONFLICT), TALER_TESTING_cmd_end () }; @@ -364,7 +364,7 @@ run (void *cls, TALER_TESTING_cmd_refresh_melt ("refresh-melt-failing", "refresh-withdraw-coin-1", - MHD_HTTP_FORBIDDEN, + MHD_HTTP_CONFLICT, NULL), /* FIXME: also test with coin that was already melted @@ -708,7 +708,7 @@ run (void *cls, ("payback-withdraw-coin-2-over", "payback-create-reserve-1", "EUR:10", - MHD_HTTP_FORBIDDEN), + MHD_HTTP_CONFLICT), TALER_TESTING_cmd_status ("payback-reserve-status-2", "payback-create-reserve-1", @@ -740,7 +740,7 @@ run (void *cls, ("expired-withdraw", "short-lived-reserve", "EUR:1", - MHD_HTTP_FORBIDDEN), + MHD_HTTP_CONFLICT), TALER_TESTING_cmd_check_bank_transfer ("check_bank_short-lived_transfer", @@ -798,7 +798,7 @@ run (void *cls, "EUR:0.5", NULL), - TALER_TESTING_cmd_payback ("payback-2b", MHD_HTTP_FORBIDDEN, + TALER_TESTING_cmd_payback ("payback-2b", MHD_HTTP_CONFLICT, "payback-withdraw-coin-2a", "EUR:0.5", NULL), diff --git a/src/lib/test_exchange_api_twisted.c b/src/lib/test_exchange_api_twisted.c index 739669b97..f648b871d 100644 --- a/src/lib/test_exchange_api_twisted.c +++ b/src/lib/test_exchange_api_twisted.c @@ -16,9 +16,8 @@ License along with TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ - /** - * @file exchange/test_exchange_api_twister.c + * @file exchange/test_exchange_api_twisted.c * @brief testcase to test exchange's HTTP API interface * @author Marcello Stanisci * @author Sree Harsha Totakura <sreeharsha@totakura.in> @@ -262,7 +261,7 @@ run (void *cls, TALER_TESTING_cmd_refund ("refund-bad-sig", - MHD_HTTP_UNAUTHORIZED, + MHD_HTTP_FORBIDDEN, "EUR:5", "EUR:0.01", "deposit-refund-1"), @@ -285,7 +284,7 @@ run (void *cls, "\"value\":\"EUR:5\"}]}", GNUNET_TIME_UNIT_MINUTES, "EUR:5", - MHD_HTTP_FORBIDDEN), + MHD_HTTP_CONFLICT), TALER_TESTING_cmd_refund ("refund-deposit-not-found", @@ -350,7 +349,7 @@ main (int argc, /* These environment variables get in the way... */ unsetenv ("XDG_DATA_HOME"); unsetenv ("XDG_CONFIG_HOME"); - GNUNET_log_setup ("test-exchange-api-new-twisted", + GNUNET_log_setup ("test-exchange-api-twisted", "DEBUG", NULL); if (NULL == (fakebank_url = TALER_TESTING_prepare_fakebank diff --git a/src/mhd/Makefile.am b/src/mhd/Makefile.am new file mode 100644 index 000000000..cc4c70735 --- /dev/null +++ b/src/mhd/Makefile.am @@ -0,0 +1,26 @@ +# This Makefile.am is in the public domain +AM_CPPFLAGS = -I$(top_srcdir)/src/include + +if USE_COVERAGE + AM_CFLAGS = --coverage -O0 + XLIB = -lgcov +endif + +lib_LTLIBRARIES = \ + libtalermhd.la + +libtalermhd_la_SOURCES = \ + mhd_config.c \ + mhd_parsing.c \ + mhd_responses.c +libtalermhd_la_LDFLAGS = \ + -version-info 0:0:0 \ + -export-dynamic -no-undefined +libtalermhd_la_LIBADD = \ + -lgnunetjson \ + $(top_builddir)/src/json/libtalerjson.la \ + $(top_builddir)/src/util/libtalerutil.la \ + -lgnunetutil \ + -ljansson \ + $(XLIB) + diff --git a/src/mhd/mhd_config.c b/src/mhd/mhd_config.c new file mode 100644 index 000000000..d4b0e9795 --- /dev/null +++ b/src/mhd/mhd_config.c @@ -0,0 +1,396 @@ +/* + This file is part of TALER + Copyright (C) 2014--2019 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 + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file mhd_config.c + * @brief functions to configure and setup MHD + * @author Florian Dold + * @author Benedikt Mueller + * @author Christian Grothoff + */ +#include "platform.h" +#include <gnunet/gnunet_util_lib.h> +#include "taler_mhd_lib.h" + + +/** + * Backlog for listen operation on UNIX domain sockets. + */ +#define UNIX_BACKLOG 500 + + +/** + * Parse the configuration to determine on which port + * or UNIX domain path we should run an HTTP service. + * + * @param cfg configuration to parse + * @param section section of the configuration to parse (usually "exchange") + * @param[out] rport set to the port number, or 0 for none + * @param[out] unix_path set to the UNIX path, or NULL for none + * @param[out] unix_mode set to the mode to be used for @a unix_path + * @return #GNUNET_OK on success + */ +int +TALER_MHD_parse_config (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *section, + uint16_t *rport, + char **unix_path, + mode_t *unix_mode) +{ + const char *choices[] = {"tcp", "unix"}; + const char *serve_type; + unsigned long long port; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_choice (cfg, + section, + "serve", + choices, + &serve_type)) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + section, + "serve", + "serve type required"); + return GNUNET_SYSERR; + } + + if (0 == strcasecmp (serve_type, "tcp")) + { + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cfg, + section, + "port", + &port)) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + section, + "port", + "port number required"); + return GNUNET_SYSERR; + } + + if ( (0 == port) || + (port > UINT16_MAX) ) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + section, + "port", + "value not in [1,65535]"); + return GNUNET_SYSERR; + } + *rport = (uint16_t) port; + *unix_path = NULL; + return GNUNET_OK; + } + if (0 == strcmp (serve_type, "unix")) + { + struct sockaddr_un s_un; + char *modestring; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, + section, + "unixpath", + unix_path)) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + section, + "unixpath", + "unixpath required"); + return GNUNET_SYSERR; + } + if (strlen (*unix_path) >= sizeof (s_un.sun_path)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "unixpath `%s' is too long\n", + *unix_path); + return GNUNET_SYSERR; + } + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + section, + "UNIXPATH_MODE", + &modestring)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + section, + "UNIXPATH_MODE"); + return GNUNET_SYSERR; + } + errno = 0; + *unix_mode = (mode_t) strtoul (modestring, NULL, 8); + if (0 != errno) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + section, + "UNIXPATH_MODE", + "must be octal number"); + GNUNET_free (modestring); + return GNUNET_SYSERR; + } + GNUNET_free (modestring); + return GNUNET_OK; + } + /* not reached */ + GNUNET_assert (0); + return GNUNET_SYSERR; +} + + +/** + * Function called for logging by MHD. + * + * @param cls closure, NULL + * @param fm format string (`printf()`-style) + * @param ap arguments to @a fm + */ +void +TALER_MHD_handle_logs (void *cls, + const char *fm, + va_list ap) +{ + static int cache; + char buf[2048]; + + (void) cls; + if (-1 == cache) + return; + if (0 == cache) + { + if (0 == + GNUNET_get_log_call_status (GNUNET_ERROR_TYPE_INFO, + "libmicrohttpd", + __FILE__, + __FUNCTION__, + __LINE__)) + { + cache = -1; + return; + } + } + cache = 1; + vsnprintf (buf, + sizeof (buf), + fm, + ap); + GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_INFO, + "libmicrohttpd", + "%s", + buf); +} + + +/** + * Open UNIX domain socket for listining at @a unix_path with + * permissions @a unix_mode. + * + * @param unix_path where to listen + * @param unix_mode access permissions to set + * @return -1 on error, otherwise the listen socket + */ +int +TALER_MHD_open_unix_path (const char *unix_path, + mode_t unix_mode) +{ + struct GNUNET_NETWORK_Handle *nh; + struct sockaddr_un *un; + int fd; + + if (sizeof (un->sun_path) <= strlen (unix_path)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "unixpath `%s' is too long\n", + unix_path); + return -1; + } + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Creating listen socket '%s' with mode %o\n", + unix_path, + unix_mode); + + if (GNUNET_OK != + GNUNET_DISK_directory_create_for_file (unix_path)) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, + "mkdir", + unix_path); + } + + un = GNUNET_new (struct sockaddr_un); + un->sun_family = AF_UNIX; + strncpy (un->sun_path, + unix_path, + sizeof (un->sun_path) - 1); + GNUNET_NETWORK_unix_precheck (un); + + if (NULL == (nh = GNUNET_NETWORK_socket_create (AF_UNIX, + SOCK_STREAM, + 0))) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, + "socket"); + GNUNET_free (un); + return -1; + } + if (GNUNET_OK != + GNUNET_NETWORK_socket_bind (nh, + (void *) un, + sizeof (struct sockaddr_un))) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, + "bind", + unix_path); + GNUNET_free (un); + GNUNET_NETWORK_socket_close (nh); + return -1; + } + GNUNET_free (un); + if (GNUNET_OK != + GNUNET_NETWORK_socket_listen (nh, + UNIX_BACKLOG)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, + "listen"); + GNUNET_NETWORK_socket_close (nh); + return -1; + } + + if (0 != chmod (unix_path, + unix_mode)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, + "chmod"); + GNUNET_NETWORK_socket_close (nh); + return -1; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "set socket '%s' to mode %o\n", + unix_path, + unix_mode); + fd = GNUNET_NETWORK_get_fd (nh); + GNUNET_NETWORK_socket_free_memory_only_ (nh); + return fd; +} + + +/** + * Bind a listen socket to the UNIX domain path + * or the TCP port and IP address as specified + * in @a cfg in section @a section. IF only a + * port was specified, set @a port and return -1. + * Otherwise, return the bound file descriptor. + * + * @param cfg configuration to parse + * @param section configuration section to use + * @param port[out] port to set, if TCP without BINDTO + * @return -1 and a port of zero on error, otherwise + * either -1 and a port, or a bound stream socket + */ +int +TALER_MHD_bind (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *section, + uint16_t *port) +{ + char *bind_to; + char *serve_unixpath; + mode_t unixpath_mode; + int fh; + char port_str[6]; + struct addrinfo hints; + struct addrinfo *res; + int ec; + struct GNUNET_NETWORK_Handle *nh; + + *port = 0; + if (GNUNET_OK != + TALER_MHD_parse_config (cfg, + section, + port, + &serve_unixpath, + &unixpath_mode)) + return -1; + if (NULL != serve_unixpath) + return TALER_MHD_open_unix_path (serve_unixpath, + unixpath_mode); + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + section, + "BIND_TO", + &bind_to)) + return -1; /* only set port */ + /* let's have fun binding... */ + GNUNET_snprintf (port_str, + sizeof (port_str), + "%u", + (unsigned int) *port); + *port = 0; /* do NOT return port in case of errors */ + memset (&hints, 0, sizeof (hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_flags = AI_PASSIVE +#ifdef AI_IDN + | AI_IDN +#endif + ; + if (0 != + (ec = getaddrinfo (bind_to, + port_str, + &hints, + &res))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to resolve BIND_TO address `%s': %s\n", + bind_to, gai_strerror (ec)); + GNUNET_free (bind_to); + return -1; + } + GNUNET_free (bind_to); + + if (NULL == (nh = GNUNET_NETWORK_socket_create (res->ai_family, + res->ai_socktype, + res->ai_protocol))) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, + "socket"); + freeaddrinfo (res); + return -1; + } + if (GNUNET_OK != + GNUNET_NETWORK_socket_bind (nh, + res->ai_addr, + res->ai_addrlen)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, + "bind"); + freeaddrinfo (res); + return -1; + } + freeaddrinfo (res); + if (GNUNET_OK != + GNUNET_NETWORK_socket_listen (nh, + UNIX_BACKLOG)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, + "listen"); + GNUNET_SCHEDULER_shutdown (); + return -1; + } + fh = GNUNET_NETWORK_get_fd (nh); + GNUNET_NETWORK_socket_free_memory_only_ (nh); + return fh; +} diff --git a/src/exchange/taler-exchange-httpd_parsing.c b/src/mhd/mhd_parsing.c index fb8932b9a..0b070ffe5 100644 --- a/src/exchange/taler-exchange-httpd_parsing.c +++ b/src/mhd/mhd_parsing.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014, 2015, 2016 GNUnet e.V. + Copyright (C) 2014--2019 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 @@ -13,21 +13,18 @@ You should have received a copy of the GNU Affero General Public License along with TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ - /** - * @file taler-exchange-httpd_parsing.c + * @file mhd_parsing.c * @brief functions to parse incoming requests (MHD arguments and JSON snippets) * @author Florian Dold * @author Benedikt Mueller * @author Christian Grothoff */ - #include "platform.h" #include <gnunet/gnunet_util_lib.h> #include <gnunet/gnunet_json_lib.h> #include "taler_json_lib.h" -#include "taler-exchange-httpd_parsing.h" -#include "taler-exchange-httpd_responses.h" +#include "taler_mhd_lib.h" /** @@ -41,7 +38,7 @@ * realizes an MHD POST processor that will (incrementally) process * JSON data uploaded to the HTTP server. It will store the required * state in the @a con_cls, which must be cleaned up using - * #TEH_PARSE_post_cleanup_callback(). + * #TALER_MHD_post_cleanup_callback(). * * @param connection the MHD connection * @param con_cls the closure (points to a `struct Buffer *`) @@ -60,11 +57,11 @@ * close HTTP session with MHD_NO) */ int -TEH_PARSE_post_json (struct MHD_Connection *connection, - void **con_cls, - const char *upload_data, - size_t *upload_data_size, - json_t **json) +TALER_MHD_parse_post_json (struct MHD_Connection *connection, + void **con_cls, + const char *upload_data, + size_t *upload_data_size, + json_t **json) { enum GNUNET_JSON_PostResult pr; @@ -76,23 +73,26 @@ TEH_PARSE_post_json (struct MHD_Connection *connection, json); switch (pr) { - case GNUNET_JSON_PR_OUT_OF_MEMORY: - return (MHD_NO == TEH_RESPONSE_reply_internal_error + return (MHD_NO == + TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, TALER_EC_PARSER_OUT_OF_MEMORY, "out of memory")) ? GNUNET_SYSERR : GNUNET_NO; case GNUNET_JSON_PR_CONTINUE: return GNUNET_YES; - case GNUNET_JSON_PR_REQUEST_TOO_LARGE: - return (MHD_NO == TEH_RESPONSE_reply_request_too_large + return (MHD_NO == + TALER_MHD_reply_request_too_large (connection)) ? GNUNET_SYSERR : GNUNET_NO; - case GNUNET_JSON_PR_JSON_INVALID: return (MHD_YES == - TEH_RESPONSE_reply_invalid_json (connection)) + TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_JSON_INVALID, + "invalid JSON uploaded")) ? GNUNET_NO : GNUNET_SYSERR; case GNUNET_JSON_PR_SUCCESS: GNUNET_break (NULL != *json); @@ -109,11 +109,12 @@ TEH_PARSE_post_json (struct MHD_Connection *connection, * to clean up our state. * * @param con_cls value as it was left by - * #TEH_PARSE_post_json(), to be cleaned up + * #TALER_MHD_post_json(), to be cleaned up */ void -TEH_PARSE_post_cleanup_callback (void *con_cls) +TALER_MHD_parse_post_cleanup_callback (void *con_cls) { + // FIXME: this should probably NOT be done with a 'void *' like this! GNUNET_JSON_post_parser_cleanup (con_cls); } @@ -134,10 +135,10 @@ TEH_PARSE_post_cleanup_callback (void *con_cls) * #GNUNET_SYSERR on internal error (error response could not be sent) */ int -TEH_PARSE_mhd_request_arg_data (struct MHD_Connection *connection, - const char *param_name, - void *out_data, - size_t out_size) +TALER_MHD_parse_request_arg_data (struct MHD_Connection *connection, + const char *param_name, + void *out_data, + size_t out_size) { const char *str; @@ -147,9 +148,10 @@ TEH_PARSE_mhd_request_arg_data (struct MHD_Connection *connection, if (NULL == str) { return (MHD_NO == - TEH_RESPONSE_reply_arg_missing (connection, - TALER_EC_PARAMETER_MISSING, - param_name)) + TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_PARAMETER_MISSING, + param_name)) ? GNUNET_SYSERR : GNUNET_NO; } if (GNUNET_OK != @@ -158,9 +160,10 @@ TEH_PARSE_mhd_request_arg_data (struct MHD_Connection *connection, out_data, out_size)) return (MHD_NO == - TEH_RESPONSE_reply_arg_invalid (connection, - TALER_EC_PARAMETER_MALFORMED, - param_name)) + TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_PARAMETER_MALFORMED, + param_name)) ? GNUNET_SYSERR : GNUNET_NO; return GNUNET_OK; } @@ -181,9 +184,9 @@ TEH_PARSE_mhd_request_arg_data (struct MHD_Connection *connection, * #GNUNET_SYSERR on internal error */ int -TEH_PARSE_json_data (struct MHD_Connection *connection, - const json_t *root, - struct GNUNET_JSON_Specification *spec) +TALER_MHD_parse_json_data (struct MHD_Connection *connection, + const json_t *root, + struct GNUNET_JSON_Specification *spec) { int ret; const char *error_json_name; @@ -198,15 +201,15 @@ TEH_PARSE_json_data (struct MHD_Connection *connection, if (NULL == error_json_name) error_json_name = "<no field>"; ret = (MHD_YES == - TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:I, s:s, s:I}", - "error", "parse error", - "code", - (json_int_t) - TALER_EC_JSON_INVALID_WITH_DETAILS, - "field", error_json_name, - "line", (json_int_t) error_line)) + TALER_MHD_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:I, s:s, s:I}", + "hint", "JSON parse error", + "code", + (json_int_t) + TALER_EC_JSON_INVALID_WITH_DETAILS, + "field", error_json_name, + "line", (json_int_t) error_line)) ? GNUNET_NO : GNUNET_SYSERR; return ret; } @@ -230,10 +233,10 @@ TEH_PARSE_json_data (struct MHD_Connection *connection, * #GNUNET_SYSERR on internal error */ int -TEH_PARSE_json_array (struct MHD_Connection *connection, - const json_t *root, - struct GNUNET_JSON_Specification *spec, - ...) +TALER_MHD_parse_json_array (struct MHD_Connection *connection, + const json_t *root, + struct GNUNET_JSON_Specification *spec, + ...) { int ret; const char *error_json_name; @@ -253,11 +256,14 @@ TEH_PARSE_json_array (struct MHD_Connection *connection, if (NULL == root) { ret = (MHD_YES == - TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:I}", - "error", "parse error", - "dimension", dim)) + TALER_MHD_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:I, s:I}", + "hint", "expected array", + "code", + (json_int_t) + TALER_EC_JSON_INVALID_WITH_DETAILS, + "dimension", dim)) ? GNUNET_NO : GNUNET_SYSERR; return ret; } @@ -270,12 +276,14 @@ TEH_PARSE_json_array (struct MHD_Connection *connection, if (NULL == error_json_name) error_json_name = "<no field>"; ret = (MHD_YES == - TEH_RESPONSE_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:s, s:I}", - "error", "parse error", - "field", error_json_name, - "line", (json_int_t) error_line)) + TALER_MHD_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:I, s:I}", + "hint", error_json_name, + "code", + (json_int_t) + TALER_EC_JSON_INVALID_WITH_DETAILS, + "line", (json_int_t) error_line)) ? GNUNET_NO : GNUNET_SYSERR; return ret; } @@ -283,4 +291,4 @@ TEH_PARSE_json_array (struct MHD_Connection *connection, } -/* end of taler-exchange-httpd_parsing.c */ +/* end of mhd_parsing.c */ diff --git a/src/mhd/mhd_responses.c b/src/mhd/mhd_responses.c new file mode 100644 index 000000000..3642e7d54 --- /dev/null +++ b/src/mhd/mhd_responses.c @@ -0,0 +1,501 @@ +/* + This file is part of TALER + Copyright (C) 2014-2019 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 + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file mhd_responses.c + * @brief API for generating HTTP replies + * @author Florian Dold + * @author Benedikt Mueller + * @author Christian Grothoff + */ +#include "platform.h" +#include <zlib.h> +#include "taler_util.h" +#include "taler_mhd_lib.h" + + +/** + * Enable checking signatures before we hand them out + * (even though we should have checked them before). + * So technically these checks are redundant, but good + * during testing. + */ +#define SANITY_CHECKS_ON 1 + + +/** + * Global options for response generation. + */ +static enum TALER_MHD_GlobalOptions TM_go; + + +/** + * Set global options for response generation + * within libtalermhd. + * + * @param go global options to use + */ +void +TALER_MHD_setup (enum TALER_MHD_GlobalOptions go) +{ + TM_go = go; +} + + +/** + * Add headers we want to return in every response. + * Useful for testing, like if we want to always close + * connections. + * + * @param response response to modify + */ +void +TALER_MHD_add_global_headers (struct MHD_Response *response) +{ + if (0 != (TM_go & TALER_MHD_GO_FORCE_CONNECTION_CLOSE)) + GNUNET_break (MHD_YES == + MHD_add_response_header (response, + MHD_HTTP_HEADER_CONNECTION, + "close")); +} + + +/** + * Is HTTP body deflate compression supported by the client? + * + * @param connection connection to check + * @return #MHD_YES if 'deflate' compression is allowed + * + * Note that right now we're ignoring q-values, which is technically + * not correct, and also do not support "*" anywhere but in a line by + * itself. This should eventually be fixed, see also + * https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html + */ +int +TALER_MHD_can_compress (struct MHD_Connection *connection) +{ + const char *ae; + const char *de; + + if (0 != (TM_go & TALER_MHD_GO_DISABLE_COMPRESSION)) + return MHD_NO; + ae = MHD_lookup_connection_value (connection, + MHD_HEADER_KIND, + MHD_HTTP_HEADER_ACCEPT_ENCODING); + if (NULL == ae) + return MHD_NO; + if (0 == strcmp (ae, + "*")) + return MHD_YES; + de = strstr (ae, + "deflate"); + if (NULL == de) + return MHD_NO; + if ( ( (de == ae) || + (de[-1] == ',') || + (de[-1] == ' ') ) && + ( (de[strlen ("deflate")] == '\0') || + (de[strlen ("deflate")] == ',') || + (de[strlen ("deflate")] == ';') ) ) + return MHD_YES; + return MHD_NO; +} + + +/** + * Try to compress a response body. Updates @a buf and @a buf_size. + * + * @param[in,out] buf pointer to body to compress + * @param[in,out] buf_size pointer to initial size of @a buf + * @return #MHD_YES if @a buf was compressed + */ +int +TALER_MHD_body_compress (void **buf, + size_t *buf_size) +{ + Bytef *cbuf; + uLongf cbuf_size; + int ret; + + cbuf_size = compressBound (*buf_size); + cbuf = malloc (cbuf_size); + if (NULL == cbuf) + return MHD_NO; + ret = compress (cbuf, + &cbuf_size, + (const Bytef *) *buf, + *buf_size); + if ( (Z_OK != ret) || + (cbuf_size >= *buf_size) ) + { + /* compression failed */ + free (cbuf); + return MHD_NO; + } + free (*buf); + *buf = (void *) cbuf; + *buf_size = (size_t) cbuf_size; + return MHD_YES; +} + + +/** + * Make JSON response object. + * + * @param json the json object + * @return MHD response object + */ +struct MHD_Response * +TALER_MHD_make_json (const json_t *json) +{ + struct MHD_Response *resp; + char *json_str; + + json_str = json_dumps (json, + JSON_INDENT (2)); + if (NULL == json_str) + { + GNUNET_break (0); + return NULL; + } + resp = MHD_create_response_from_buffer (strlen (json_str), + json_str, + MHD_RESPMEM_MUST_FREE); + if (NULL == resp) + { + free (json_str); + GNUNET_break (0); + return NULL; + } + TALER_MHD_add_global_headers (resp); + GNUNET_break (MHD_YES == + MHD_add_response_header (resp, + MHD_HTTP_HEADER_CONTENT_TYPE, + "application/json")); + return resp; +} + + +/** + * Send JSON object as response. + * + * @param connection the MHD connection + * @param json the json object + * @param response_code the http response code + * @return MHD result code + */ +int +TALER_MHD_reply_json (struct MHD_Connection *connection, + const json_t *json, + unsigned int response_code) +{ + struct MHD_Response *resp; + void *json_str; + size_t json_len; + int ret; + int comp; + + json_str = json_dumps (json, + JSON_INDENT (2)); + if (NULL == json_str) + { + /** + * This log helps to figure out which + * function called this one and assert-failed. + */ + TALER_LOG_ERROR ("Aborting json-packing for HTTP code: %u\n", + response_code); + + GNUNET_assert (0); + return MHD_NO; + } + json_len = strlen (json_str); + /* try to compress the body */ + comp = MHD_NO; + if (MHD_YES == + TALER_MHD_can_compress (connection)) + comp = TALER_MHD_body_compress (&json_str, + &json_len); + resp = MHD_create_response_from_buffer (json_len, + json_str, + MHD_RESPMEM_MUST_FREE); + if (NULL == resp) + { + free (json_str); + GNUNET_break (0); + return MHD_NO; + } + TALER_MHD_add_global_headers (resp); + GNUNET_break (MHD_YES == + MHD_add_response_header (resp, + MHD_HTTP_HEADER_CONTENT_TYPE, + "application/json")); + if (MHD_YES == comp) + { + /* Need to indicate to client that body is compressed */ + if (MHD_NO == + MHD_add_response_header (resp, + MHD_HTTP_HEADER_CONTENT_ENCODING, + "deflate")) + { + GNUNET_break (0); + MHD_destroy_response (resp); + return MHD_NO; + } + } + ret = MHD_queue_response (connection, + response_code, + resp); + MHD_destroy_response (resp); + return ret; +} + + +/** + * Function to call to handle the request by building a JSON + * reply from a format string and varargs. + * + * @param connection the MHD connection to handle + * @param response_code HTTP response code to use + * @param fmt format string for pack + * @param ... varargs + * @return MHD result code + */ +int +TALER_MHD_reply_json_pack (struct MHD_Connection *connection, + unsigned int response_code, + const char *fmt, + ...) +{ + json_t *json; + va_list argp; + int ret; + json_error_t jerror; + + va_start (argp, fmt); + json = json_vpack_ex (&jerror, 0, fmt, argp); + va_end (argp); + if (NULL == json) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to pack JSON with format `%s': %s\n", + fmt, + jerror.text); + GNUNET_break (0); + return MHD_NO; + } + ret = TALER_MHD_reply_json (connection, + json, + response_code); + json_decref (json); + return ret; +} + + +/** + * Make JSON response object. + * + * @param fmt format string for pack + * @param ... varargs + * @return MHD response object + */ +struct MHD_Response * +TALER_MHD_make_json_pack (const char *fmt, + ...) +{ + json_t *json; + va_list argp; + struct MHD_Response *ret; + json_error_t jerror; + + va_start (argp, fmt); + json = json_vpack_ex (&jerror, + 0, + fmt, + argp); + va_end (argp); + if (NULL == json) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to pack JSON with format `%s': %s\n", + fmt, + jerror.text); + GNUNET_break (0); + return MHD_NO; + } + ret = TALER_MHD_make_json (json); + json_decref (json); + return ret; +} + + +/** + * Create a response indicating an internal error. + * + * @param ec error code to return + * @param hint hint about the internal error's nature + * @return a MHD response object + */ +struct MHD_Response * +TALER_MHD_make_error (enum TALER_ErrorCode ec, + const char *hint) +{ + return TALER_MHD_make_json_pack ("{s:I, s:s}", + "code", (json_int_t) ec, + "hint", hint); +} + + +/** + * Send a response indicating an error. + * + * @param connection the MHD connection to use + * @param ec error code uniquely identifying the error + * @param http_status HTTP status code to use + * @param hint human readable hint about the error + * @return a MHD result code + */ +int +TALER_MHD_reply_with_error (struct MHD_Connection *connection, + unsigned int http_status, + enum TALER_ErrorCode ec, + const char *hint) +{ + return TALER_MHD_reply_json_pack (connection, + http_status, + "{s:I, s:s}", + "code", (json_int_t) ec, + "hint", hint); +} + + +/** + * Send a response indicating that the request was too big. + * + * @param connection the MHD connection to use + * @return a MHD result code + */ +int +TALER_MHD_reply_request_too_large (struct MHD_Connection *connection) +{ + struct MHD_Response *resp; + int ret; + + resp = MHD_create_response_from_buffer (0, + NULL, + MHD_RESPMEM_PERSISTENT); + if (NULL == resp) + return MHD_NO; + TALER_MHD_add_global_headers (resp); + ret = MHD_queue_response (connection, + MHD_HTTP_REQUEST_ENTITY_TOO_LARGE, + resp); + MHD_destroy_response (resp); + return ret; +} + + +/** + * Function to call to handle the request by sending + * back a redirect to the AGPL source code. + * + * @param connection the MHD connection to handle + * @param url where to redirect for the sources + * @return MHD result code + */ +int +TALER_MHD_reply_agpl (struct MHD_Connection *connection, + const char *url) +{ + const char *agpl = + "This server is licensed under the Affero GPL. You will now be redirected to the source code."; + struct MHD_Response *response; + int ret; + + response = MHD_create_response_from_buffer (strlen (agpl), + (void *) agpl, + MHD_RESPMEM_PERSISTENT); + if (NULL == response) + { + GNUNET_break (0); + return MHD_NO; + } + TALER_MHD_add_global_headers (response); + GNUNET_break (MHD_YES == + MHD_add_response_header (response, + MHD_HTTP_HEADER_CONTENT_TYPE, + "text/plain")); + if (MHD_NO == + MHD_add_response_header (response, + MHD_HTTP_HEADER_LOCATION, + url)) + { + GNUNET_break (0); + MHD_destroy_response (response); + return MHD_NO; + } + ret = MHD_queue_response (connection, + MHD_HTTP_FOUND, + response); + MHD_destroy_response (response); + return ret; +} + + +/** + * Function to call to handle the request by sending + * back static data. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param http_status status code to return + * @param mime_type content-type to use + * @param body response payload + * @param body_size number of bytes in @a body + * @return MHD result code + */ +int +TALER_MHD_reply_static (struct MHD_Connection *connection, + unsigned int http_status, + const char *mime_type, + const char *body, + size_t body_size) +{ + struct MHD_Response *response; + int ret; + + response = MHD_create_response_from_buffer (body_size, + (void *) body, + MHD_RESPMEM_PERSISTENT); + if (NULL == response) + { + GNUNET_break (0); + return MHD_NO; + } + TALER_MHD_add_global_headers (response); + if (NULL != mime_type) + GNUNET_break (MHD_YES == + MHD_add_response_header (response, + MHD_HTTP_HEADER_CONTENT_TYPE, + mime_type)); + ret = MHD_queue_response (connection, + http_status, + response); + MHD_destroy_response (response); + return ret; +} + + +/* end of mhd_responses.c */ diff --git a/src/util/crypto.c b/src/util/crypto.c index 077f049eb..cf351d3f2 100644 --- a/src/util/crypto.c +++ b/src/util/crypto.c @@ -191,32 +191,6 @@ TALER_link_recover_transfer_secret (const struct /** - * Set the bits in the private EdDSA key so that they match - * the specification. - * - * @param[in,out] pk private key to patch - */ -static void -patch_private_key (struct GNUNET_CRYPTO_EddsaPrivateKey *pk) -{ - uint8_t *p = (uint8_t *) pk; - - /* Taken from like 170-172 of libgcrypt/cipher/ecc.c - * We note that libgcrypt stores the private key in the reverse order - * from many Ed25519 implementatons. */ - p[0] &= 0x7f; /* Clear bit 255. */ - p[0] |= 0x40; /* Set bit 254. */ - p[31] &= 0xf8; /* Clear bits 2..0 so that d mod 8 == 0 */ - - /* FIXME: Run GNUNET_CRYPTO_ecdhe_key_create several times and inspect - * the output to verify that the same bits are set and cleared. - * Is it worth also adding a test case that runs gcry_pk_testkey on - * this key after first parsing it into libgcrypt's s-expression mess - * ala decode_private_eddsa_key from gnunet/src/util/crypto_ecc.c? - * It'd run check_secret_key but not test_keys from libgcrypt/cipher/ecc.c */} - - -/** * Setup information for a fresh coin. * * @param secret_seed seed to use for KDF to derive coin keys @@ -240,7 +214,6 @@ TALER_planchet_setup_refresh (const struct TALER_TransferSecretP *secret_seed, "taler-coin-derivation", strlen ("taler-coin-derivation"), NULL, 0)); - patch_private_key (&ps->coin_priv.eddsa_priv); } @@ -255,7 +228,6 @@ TALER_planchet_setup_random (struct TALER_PlanchetSecretsP *ps) GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG, ps, sizeof (*ps)); - patch_private_key (&ps->coin_priv.eddsa_priv); } |