diff options
author | Christian Grothoff <christian@grothoff.org> | 2015-01-16 13:50:07 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2015-01-16 13:50:07 +0100 |
commit | f58fb4fc21be694096ae223fe0990ab93a52e815 (patch) | |
tree | 6bb6f4bec9d3f7ba8b4dc8a72d577f650c7d0211 /src | |
parent | 0430d6fb031d1713a39a996068387c3ab2c36c2d (diff) | |
download | exchange-f58fb4fc21be694096ae223fe0990ab93a52e815.tar.xz |
starting to separate out response generation API and parsing APIs
Diffstat (limited to 'src')
-rw-r--r-- | src/mint/Makefile.am | 3 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd.c | 3 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_deposit.c | 29 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_keys.c | 2 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_mhd.c | 167 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_mhd.h | 23 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_parsing.c (renamed from src/mint/taler-mint-httpd_json.c) | 242 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_parsing.h (renamed from src/mint/taler-mint-httpd_json.h) | 81 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_refresh.c | 137 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_responses.c | 146 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_responses.h | 93 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_withdraw.c | 71 |
12 files changed, 579 insertions, 418 deletions
diff --git a/src/mint/Makefile.am b/src/mint/Makefile.am index eff126a07..4a2e775da 100644 --- a/src/mint/Makefile.am +++ b/src/mint/Makefile.am @@ -61,8 +61,9 @@ taler_mint_reservemod_LDFLAGS = \ taler_mint_httpd_SOURCES = \ taler-mint-httpd.c \ + taler-mint-httpd_parsing.c taler-mint-httpd_parsing.h \ + taler-mint-httpd_responses.c taler-mint-httpd_responses.h \ taler-mint-httpd_mhd.c \ - taler-mint-httpd_json.c taler-mint-httpd_json.h \ taler-mint-httpd_keys.c \ taler-mint-httpd_deposit.c \ taler-mint-httpd_withdraw.c \ diff --git a/src/mint/taler-mint-httpd.c b/src/mint/taler-mint-httpd.c index 14dfa657c..61d0bbdce 100644 --- a/src/mint/taler-mint-httpd.c +++ b/src/mint/taler-mint-httpd.c @@ -32,7 +32,7 @@ #include "taler_signatures.h" #include "taler_rsa.h" #include "taler_json_lib.h" -#include "taler-mint-httpd_json.h" +#include "taler-mint-httpd_parsing.h" #include "taler-mint-httpd_mhd.h" #include "taler-mint-httpd_keys.h" #include "taler-mint-httpd_deposit.h" @@ -372,4 +372,3 @@ main (int argc, char *const *argv) MHD_stop_daemon (mydaemon); return (GNUNET_OK == ret) ? 0 : 1; } - diff --git a/src/mint/taler-mint-httpd_deposit.c b/src/mint/taler-mint-httpd_deposit.c index b8bcc87db..8c040b691 100644 --- a/src/mint/taler-mint-httpd_deposit.c +++ b/src/mint/taler-mint-httpd_deposit.c @@ -31,9 +31,10 @@ #include "taler_signatures.h" #include "taler_rsa.h" #include "taler_json_lib.h" -#include "taler-mint-httpd_json.h" +#include "taler-mint-httpd_parsing.h" #include "taler-mint-httpd_keys.h" #include "taler-mint-httpd_deposit.h" +#include "taler-mint-httpd_responses.h" /** @@ -48,8 +49,11 @@ helper_deposit_send_response_success (struct MHD_Connection *connection, struct Deposit *deposit) { // FIXME: return more information here - return request_send_json_pack (connection, MHD_HTTP_OK, - "{s:s}", "status", "DEPOSIT_OK"); + return TALER_MINT_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:s}", + "status", + "DEPOSIT_OK"); } @@ -199,9 +203,11 @@ TALER_MINT_handler_deposit (struct RequestHandler *rh, // FIXME: in the future, check if there's enough credits // left on the coin. For now: refuse // FIXME: return more information here - return request_send_json_pack (connection, MHD_HTTP_FORBIDDEN, - "{s:s}", - "error", "double spending"); + return TALER_MINT_reply_json_pack (connection, + MHD_HTTP_FORBIDDEN, + "{s:s}", + "error", + "double spending"); } if (GNUNET_SYSERR == res) @@ -221,9 +227,10 @@ TALER_MINT_handler_deposit (struct RequestHandler *rh, // coin must have been refreshed // FIXME: check // FIXME: return more information here - return request_send_json_pack (connection, MHD_HTTP_FORBIDDEN, - "{s:s}", - "error", "coin was refreshed"); + return TALER_MINT_reply_json_pack (connection, + MHD_HTTP_FORBIDDEN, + "{s:s}", + "error", "coin was refreshed"); } if (GNUNET_SYSERR == res) { @@ -252,7 +259,9 @@ TALER_MINT_handler_deposit (struct RequestHandler *rh, EXITIF_exit: if (NULL != resp) - res = send_response_json (connection, resp, resp_code); + res = TALER_MINT_reply_json (connection, + resp, + resp_code); else res = MHD_NO; if (NULL != wire) diff --git a/src/mint/taler-mint-httpd_keys.c b/src/mint/taler-mint-httpd_keys.c index 6d6e9468d..149e44d3f 100644 --- a/src/mint/taler-mint-httpd_keys.c +++ b/src/mint/taler-mint-httpd_keys.c @@ -31,7 +31,7 @@ #include "taler_signatures.h" #include "taler_rsa.h" #include "taler_json_lib.h" -#include "taler-mint-httpd_json.h" +#include "taler-mint-httpd_parsing.h" #include "taler-mint-httpd_keys.h" diff --git a/src/mint/taler-mint-httpd_mhd.c b/src/mint/taler-mint-httpd_mhd.c index d78f36d95..ed8a6eeda 100644 --- a/src/mint/taler-mint-httpd_mhd.c +++ b/src/mint/taler-mint-httpd_mhd.c @@ -16,7 +16,9 @@ /** * @file taler-mint-httpd_mhd.c - * @brief helpers for MHD interaction + * @brief helpers for MHD interaction; these are TALER_MINT_handler_ functions + * that generate simple MHD replies that do not require any real operations + * to be performed (error handling, static pages, etc.) * @author Florian Dold * @author Benedikt Mueller * @author Christian Grothoff @@ -27,9 +29,10 @@ #include <microhttpd.h> #include <libpq-fe.h> #include <pthread.h> -#include "taler-mint-httpd_json.h" +#include "taler-mint-httpd_responses.h" #include "taler-mint-httpd.h" #include "taler-mint-httpd_mhd.h" +#include "taler-mint-httpd_responses.h" /** @@ -123,63 +126,6 @@ TALER_MINT_handler_agpl_redirect (struct RequestHandler *rh, /** * Function to call to handle the request by building a JSON - * reply from varargs. - * - * @param rh context of the handler - * @param connection the MHD connection to handle - * @param[IN|OUT] connection_cls the connection's closure (can be updated) - * @param response_code HTTP response code to use - * @param do_cache can the response be cached? (0: no, 1: yes) - * @param fmt format string for pack - * @param ... varargs - * @return MHD result code - */ -int -TALER_MINT_helper_send_json_pack (struct RequestHandler *rh, - struct MHD_Connection *connection, - void *connection_cls, - int response_code, - int do_cache, - const char *fmt, - ...) -{ - int ret; - json_t *json; - va_list argp; - char *json_str; - struct MHD_Response *response; - - va_start (argp, fmt); - json = json_vpack_ex (NULL, 0, fmt, argp); - va_end (argp); - if (NULL == json) - return MHD_NO; - json_str = json_dumps (json, JSON_INDENT(2)); - json_decref (json); - if (NULL == json_str) - return MHD_NO; - response = MHD_create_response_from_buffer (strlen (json_str), - json_str, - MHD_RESPMEM_MUST_FREE); - if (NULL == response) - { - free (json_str); - return MHD_NO; - } - if (NULL != rh->mime_type) - (void) MHD_add_response_header (response, - MHD_HTTP_HEADER_CONTENT_TYPE, - rh->mime_type); - ret = MHD_queue_response (connection, - response_code, - response); - MHD_destroy_response (response); - return ret; -} - - -/** - * Function to call to handle the request by building a JSON * reply with an error message from @a rh. * * @param rh context of the handler @@ -196,105 +142,12 @@ TALER_MINT_handler_send_json_pack_error (struct RequestHandler *rh, const char *upload_data, size_t *upload_data_size) { - return TALER_MINT_helper_send_json_pack (rh, - connection, - connection_cls, - 1, /* caching enabled */ - rh->response_code, - "{s:s}", - "error", - rh->data); + return TALER_MINT_reply_json_pack (connection, + rh->response_code, + "{s:s}", + "error", + rh->data); } -/** - * Send a response for an invalid argument. - * - * @param connection the MHD connection to use - * @param param_name the parameter that is missing - * @return a GNUnet result code - */ -static int -request_arg_invalid (struct MHD_Connection *connection, - const char *param_name) -{ - json_t *json; - json = json_pack ("{ s:s, s:s }", - "error", "invalid parameter", - "parameter", param_name); - if (MHD_YES != send_response_json (connection, json, MHD_HTTP_BAD_REQUEST)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - return GNUNET_NO; -} - - -/** - * Get a GET paramater that is a string, - * or send an error response if the parameter is missing. - * - * @param connection the connection to get the parameter from / - * send the error response to - * @param param_name the parameter name - * @param str pointer to store the parameter string, - * must be freed by the caller - * @return GNUNET_YES if the parameter is present and valid, - * GNUNET_NO if the parameter is missing - * GNUNET_SYSERR on internal error - */ -static int -request_arg_require_string (struct MHD_Connection *connection, - const char *param_name, - const char **str) -{ - *str = MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, param_name); - if (NULL == *str) - { - if (MHD_NO == - request_send_json_pack (connection, MHD_HTTP_BAD_REQUEST, - "{ s:s, s:s }", - "error", "missing parameter", - "parameter", param_name)) - return GNUNET_SYSERR; - return GNUNET_NO; - } - return GNUNET_OK; -} - - -/** - * Extraxt 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 -TALER_MINT_mhd_request_arg_data (struct MHD_Connection *connection, - const char *param_name, - void *out_data, - size_t out_size) -{ - const char *str; - int ret; - - if (GNUNET_OK != (ret = request_arg_require_string (connection, param_name, &str))) - return ret; - if (GNUNET_OK != GNUNET_STRINGS_string_to_data (str, strlen (str), out_data, out_size)) - return request_arg_invalid (connection, param_name); - return GNUNET_OK; -} - - - /* end of taler-mint-httpd_mhd.c */ diff --git a/src/mint/taler-mint-httpd_mhd.h b/src/mint/taler-mint-httpd_mhd.h index 29ab7f64b..1390a2753 100644 --- a/src/mint/taler-mint-httpd_mhd.h +++ b/src/mint/taler-mint-httpd_mhd.h @@ -16,7 +16,7 @@ /** * @file taler-mint-httpd_mhd.h - * @brief helpers for MHD interaction + * @brief helpers for MHD interaction, used to generate simple responses * @author Florian Dold * @author Benedikt Mueller * @author Christian Grothoff @@ -108,25 +108,4 @@ TALER_MINT_handler_send_json_pack_error (struct RequestHandler *rh, size_t *upload_data_size); -/** - * Extraxt 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 -TALER_MINT_mhd_request_arg_data (struct MHD_Connection *connection, - const char *param_name, - void *out_data, - size_t out_size); - #endif diff --git a/src/mint/taler-mint-httpd_json.c b/src/mint/taler-mint-httpd_parsing.c index e9183073f..a976c0c06 100644 --- a/src/mint/taler-mint-httpd_json.c +++ b/src/mint/taler-mint-httpd_parsing.c @@ -1,7 +1,31 @@ +/* + This file is part of TALER + (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, If not, see <http://www.gnu.org/licenses/> +*/ + +/** + * @file taler-mint-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 "taler-mint-httpd_json.h" - +#include "taler-mint-httpd_parsing.h" +#include "taler-mint-httpd_responses.h" /** @@ -49,7 +73,11 @@ struct Buffer * @return a GNUnet result code */ static int -buffer_init (struct Buffer *buf, const void *data, size_t data_size, size_t alloc_size, size_t max_size) +buffer_init (struct Buffer *buf, + const void *data, + size_t data_size, + size_t alloc_size, + size_t max_size) { if (data_size > max_size || alloc_size > max_size) return GNUNET_SYSERR; @@ -87,7 +115,10 @@ buffer_deinit (struct Buffer *buf) * GNUNET_SYSERR on fatal error (out of memory?) */ static int -buffer_append (struct Buffer *buf, const void *data, size_t data_size, size_t max_size) +buffer_append (struct Buffer *buf, + const void *data, + size_t data_size, + size_t max_size) { if (buf->fill + data_size > max_size) return GNUNET_NO; @@ -111,63 +142,6 @@ buffer_append (struct Buffer *buf, const void *data, size_t data_size, size_t ma /** - * Send JSON object as response. Decreases the reference count of the - * JSON object. - * - * @param connection the MHD connection - * @param json the json object - * @param status_code the http status code - * @return MHD result code - */ -int -send_response_json (struct MHD_Connection *connection, - json_t *json, - unsigned int status_code) -{ - struct MHD_Response *resp; - char *json_str; - - json_str = json_dumps (json, JSON_INDENT(2)); - json_decref (json); - resp = MHD_create_response_from_buffer (strlen (json_str), json_str, - MHD_RESPMEM_MUST_FREE); - if (NULL == resp) - return MHD_NO; - return MHD_queue_response (connection, status_code, resp); -} - - -/** - * Send a JSON object via an MHD connection, - * specified with the JANSSON pack syntax (see json_pack). - * - * @param connection connection to send the JSON over - * @param http_code HTTP status for the response - * @param fmt format string for pack - * @param ... varargs - * @return MHD_YES on success or MHD_NO on error - */ -int -request_send_json_pack (struct MHD_Connection *connection, - unsigned int http_code, - const char *fmt, ...) -{ - json_t *msg; - va_list argp; - int ret; - - va_start(argp, fmt); - msg = json_vpack_ex (NULL, 0, fmt, argp); - va_end(argp); - if (NULL == msg) - return MHD_NO; - ret = send_response_json (connection, msg, http_code); - json_decref (msg); - return ret; -} - - -/** * Process a POST request containing a JSON object. * * @param connection the MHD connection @@ -195,8 +169,12 @@ process_post_json (struct MHD_Connection *connection, /* We are seeing a fresh POST request. */ r = GNUNET_new (struct Buffer); - if (GNUNET_OK != buffer_init (r, upload_data, *upload_data_size, - REQUEST_BUFFER_INITIAL, REQUEST_BUFFER_MAX)) + if (GNUNET_OK != + buffer_init (r, + upload_data, + *upload_data_size, + REQUEST_BUFFER_INITIAL, + REQUEST_BUFFER_MAX)) { *con_cls = NULL; buffer_deinit (r); @@ -211,8 +189,11 @@ process_post_json (struct MHD_Connection *connection, { /* We are seeing an old request with more data available. */ - if (GNUNET_OK != buffer_append (r, upload_data, *upload_data_size, - REQUEST_BUFFER_MAX)) + if (GNUNET_OK != + buffer_append (r, + upload_data, + *upload_data_size, + REQUEST_BUFFER_MAX)) { /* Request too long or we're out of memory. */ @@ -232,11 +213,14 @@ process_post_json (struct MHD_Connection *connection, GNUNET_free (r); if (NULL == *json) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Can't parse JSON request body\n"); - return request_send_json_pack (connection, MHD_HTTP_BAD_REQUEST, - GNUNET_NO, GNUNET_SYSERR, - "{s:s}", - "error", "invalid json"); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Can't parse JSON request body\n"); + return (MHD_YES == + TALER_MINT_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s}", + "error", "invalid json")) + ? GNUNET_NO : GNUNET_SYSERR; } *con_cls = NULL; @@ -284,12 +268,14 @@ request_json_require_nav (struct MHD_Connection *connection, root = json_object_get (root, fname); if (NULL == root) { - - (void) request_send_json_pack (connection, MHD_HTTP_BAD_REQUEST, - 0, 0, - "{s:s,s:o}", - "error", "missing field in JSON", - "path", path); + /* FIXME: can't IGNORE this return value! */ + (void) TALER_MINT_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s,s:o}", + "error", + "missing field in JSON", + "path", + path); ignore = GNUNET_YES; break; } @@ -304,11 +290,12 @@ request_json_require_nav (struct MHD_Connection *connection, root = json_array_get (root, fnum); if (NULL == root) { - (void) request_send_json_pack (connection, MHD_HTTP_BAD_REQUEST, - 0, 0, - "{s:s, s:o}", - "error", "missing index in JSON", - "path", path); + /* FIXME: can't IGNORE this return value! */ + (void) TALER_MINT_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:o}", + "error", "missing index in JSON", + "path", path); ignore = GNUNET_YES; break; } @@ -327,22 +314,27 @@ request_json_require_nav (struct MHD_Connection *connection, str = json_string_value (root); if (NULL == str) { - (void) request_send_json_pack (connection, MHD_HTTP_BAD_REQUEST, - 0, 0, - "{s:s, s:o}", - "error", "string expected", - "path", path); + /* FIXME: can't IGNORE this return value! */ + (void) TALER_MINT_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:o}", + "error", + "string expected", + "path", + path); return GNUNET_NO; } res = GNUNET_STRINGS_string_to_data (str, strlen (str), where, len); if (GNUNET_OK != res) { - (void) request_send_json_pack (connection, MHD_HTTP_BAD_REQUEST, - 0, 0, - "{s:s,s:o}", - "error", "malformed binary data in JSON", - "path", path); + /* FIXME: can't IGNORE this return value! */ + (void) TALER_MINT_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s,s:o}", + "error", + "malformed binary data in JSON", + "path", path); return GNUNET_NO; } return GNUNET_YES; @@ -372,11 +364,13 @@ request_json_require_nav (struct MHD_Connection *connection, *where, *len); if (GNUNET_OK != res) { - (void) request_send_json_pack (connection, MHD_HTTP_BAD_REQUEST, - 0, 0, - "{s:s, s:o}", - "error", "malformed binary data in JSON", - "path", path); + /* FIXME: can't IGNORE this return value! */ + (void) TALER_MINT_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:o}", + "error", + "malformed binary data in JSON", + "path", path); return GNUNET_NO; } } @@ -393,13 +387,14 @@ request_json_require_nav (struct MHD_Connection *connection, return GNUNET_NO; if (typ != -1 && json_typeof (root) != typ) { - (void) request_send_json_pack (connection, MHD_HTTP_BAD_REQUEST, - 0, 0, - "{s:s, s:i, s:i s:o}", - "error", "wrong JSON field type", - "type_expected", typ, - "type_actual", json_typeof (root), - "path", path); + /* FIXME: can't IGNORE this return value! */ + (void) TALER_MINT_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:i, s:i s:o}", + "error", "wrong JSON field type", + "type_expected", typ, + "type_actual", json_typeof (root), + "path", path); return GNUNET_NO; } *r_json = root; @@ -414,4 +409,45 @@ request_json_require_nav (struct MHD_Connection *connection, } +/** + * 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 +TALER_MINT_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 == + TALER_MINT_reply_arg_missing (connection, param_name)) + ? GNUNET_SYSERR : GNUNET_NO; + } + if (GNUNET_OK != + GNUNET_STRINGS_string_to_data (str, + strlen (str), + out_data, + out_size)) + return (MHD_NO == + TALER_MINT_reply_arg_invalid (connection, param_name)) + ? GNUNET_SYSERR : GNUNET_NO; + return GNUNET_OK; +} diff --git a/src/mint/taler-mint-httpd_json.h b/src/mint/taler-mint-httpd_parsing.h index da601401f..2c6bb073c 100644 --- a/src/mint/taler-mint-httpd_json.h +++ b/src/mint/taler-mint-httpd_parsing.h @@ -1,4 +1,26 @@ +/* + This file is part of TALER + (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, If not, see <http://www.gnu.org/licenses/> +*/ + +/** + * @file taler-mint-httpd_parsing.h + * @brief functions to parse incoming requests + * @author Florian Dold + * @author Benedikt Mueller + * @author Christian Grothoff + */ #ifndef TALER_MICROHTTPD_LIB_H_ #define TALER_MICROHTTPD_LIB_H_ @@ -45,38 +67,6 @@ enum }; - -/** - * Send JSON object as response. Decreases - * the reference count of the JSON object. - * - * @param connection the MHD connection - * @param json the json object - * @param status_code the http status code - * @return MHD result code (MHD_YES on success) - */ -int -send_response_json (struct MHD_Connection *connection, - json_t *json, - unsigned int status_code); - - -/** - * Send a JSON object via an MHD connection, - * specified with the JANSSON pack syntax (see json_pack). - * - * @param connection connection to send the JSON over - * @param http_code HTTP status for the response - * @param fmt format string for pack - * @param ... varargs - * @return MHD_YES on success or MHD_NO on error - */ -int -request_send_json_pack (struct MHD_Connection *connection, - unsigned int http_code, - const char *fmt, ...); - - /** * Process a POST request containing a JSON object. * @@ -116,4 +106,31 @@ int request_json_require_nav (struct MHD_Connection *connection, const json_t *root, ...); + + + +/** + * Extraxt 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 +TALER_MINT_mhd_request_arg_data (struct MHD_Connection *connection, + const char *param_name, + void *out_data, + size_t out_size); + + + + #endif /* TALER_MICROHTTPD_LIB_H_ */ diff --git a/src/mint/taler-mint-httpd_refresh.c b/src/mint/taler-mint-httpd_refresh.c index 888e7de3b..73b474194 100644 --- a/src/mint/taler-mint-httpd_refresh.c +++ b/src/mint/taler-mint-httpd_refresh.c @@ -31,10 +31,11 @@ #include "taler_signatures.h" #include "taler_rsa.h" #include "taler_json_lib.h" -#include "taler-mint-httpd_json.h" +#include "taler-mint-httpd_parsing.h" #include "taler-mint-httpd_keys.h" #include "taler-mint-httpd_mhd.h" #include "taler-mint-httpd_refresh.h" +#include "taler-mint-httpd_responses.h" /** @@ -228,10 +229,10 @@ check_confirm_signature (struct MHD_Connection *connection, coin_pub)) { if (MHD_YES != - request_send_json_pack (connection, - MHD_HTTP_UNAUTHORIZED, - "{s:s}", - "error", "signature invalid")) + TALER_MINT_reply_json_pack (connection, + MHD_HTTP_UNAUTHORIZED, + "{s:s}", + "error", "signature invalid")) return GNUNET_SYSERR; return GNUNET_NO; } @@ -356,15 +357,19 @@ refresh_accept_melts (struct MHD_Connection *connection, dki = &(TALER_MINT_get_denom_key (key_state, &coin_public_info.denom_pub)->issue); if (NULL == dki) - return (MHD_YES == request_send_json_pack (connection, MHD_HTTP_NOT_FOUND, - "{s:s}", - "error", "denom not found")) + return (MHD_YES == + TALER_MINT_reply_json_pack (connection, + MHD_HTTP_NOT_FOUND, + "{s:s}", + "error", "denom not found")) ? GNUNET_NO : GNUNET_SYSERR; if (GNUNET_OK != TALER_MINT_test_coin_valid (key_state, &coin_public_info)) - return (MHD_YES == request_send_json_pack (connection, MHD_HTTP_NOT_FOUND, - "{s:s}", - "error", "coin invalid")) + return (MHD_YES == + TALER_MINT_reply_json_pack (connection, + MHD_HTTP_NOT_FOUND, + "{s:s}", + "error", "coin invalid")) ? GNUNET_NO : GNUNET_SYSERR; res = TALER_MINT_DB_get_known_coin (db_conn, &coin_public_info.coin_pub, @@ -379,9 +384,13 @@ refresh_accept_melts (struct MHD_Connection *connection, if (GNUNET_YES == res) { if (GNUNET_YES == known_coin.is_refreshed) - return (MHD_YES == request_send_json_pack (connection, MHD_HTTP_NOT_FOUND, - "{s:s}", - "error", "coin already refreshed")) ? GNUNET_NO : GNUNET_SYSERR; + return (MHD_YES == + TALER_MINT_reply_json_pack (connection, + MHD_HTTP_NOT_FOUND, + "{s:s}", + "error", + "coin already refreshed")) + ? GNUNET_NO : GNUNET_SYSERR; } else { @@ -413,9 +422,11 @@ refresh_accept_melts (struct MHD_Connection *connection, * pay the refreshing fees of the coin. */ if (TALER_amount_cmp (coin_gain, TALER_amount_ntoh (dki->fee_refresh)) < 0) - return (MHD_YES == request_send_json_pack (connection, MHD_HTTP_NOT_FOUND, - "{s:s}", - "error", "depleted")) ? GNUNET_NO : GNUNET_SYSERR; + return (MHD_YES == + TALER_MINT_reply_json_pack (connection, + MHD_HTTP_NOT_FOUND, + "{s:s}", + "error", "depleted")) ? GNUNET_NO : GNUNET_SYSERR; coin_gain = TALER_amount_subtract (coin_gain, TALER_amount_ntoh (dki->fee_refresh)); @@ -472,9 +483,9 @@ helper_refresh_send_melt_response (struct MHD_Connection *connection, json_object_set (root, "signature", sig_json); } - return send_response_json (connection, - root, - MHD_HTTP_OK); + return TALER_MINT_reply_json (connection, + root, + MHD_HTTP_OK); } @@ -524,9 +535,10 @@ request_json_check_signature (struct MHD_Connection *connection, if (purpose_num != ntohl (purpose->purpose)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "signature invalid (purpose wrong)\n"); - return request_send_json_pack (connection, MHD_HTTP_BAD_REQUEST, - "{s:s}", - "error", "signature invalid (purpose)"); + return TALER_MINT_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s}", + "error", "signature invalid (purpose)"); } res = request_json_require_nav (connection, root, @@ -543,10 +555,11 @@ request_json_check_signature (struct MHD_Connection *connection, if (size != ntohl (purpose->size)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "signature invalid (size wrong)\n"); - return request_send_json_pack (connection, MHD_HTTP_BAD_REQUEST, - GNUNET_NO, GNUNET_SYSERR, - "{s:s}", - "error", "signature invalid (size)"); + return TALER_MINT_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + GNUNET_NO, GNUNET_SYSERR, + "{s:s}", + "error", "signature invalid (size)"); } if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (purpose_num, @@ -555,9 +568,11 @@ request_json_check_signature (struct MHD_Connection *connection, pub)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "signature invalid (did not verify)\n"); - return request_send_json_pack (connection, MHD_HTTP_UNAUTHORIZED, - "{s:s}", - "error", "invalid signature (verification)"); + return TALER_MINT_reply_json_pack (connection, + MHD_HTTP_UNAUTHORIZED, + "{s:s}", + "error", + "invalid signature (verification)"); } return GNUNET_OK; @@ -705,10 +720,11 @@ TALER_MINT_handler_refresh_melt (struct RequestHandler *rh, if (NULL == melt_sig_json) { GNUNET_break (GNUNET_OK == TALER_MINT_DB_rollback (db_conn)); - return request_send_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s}", - "error", "melt_signature missing"); + return TALER_MINT_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s}", + "error", + "melt_signature missing"); } body.melt_hash = melt_hash; @@ -734,9 +750,11 @@ TALER_MINT_handler_refresh_melt (struct RequestHandler *rh, { GNUNET_break (GNUNET_OK == TALER_MINT_DB_rollback (db_conn)); - return request_send_json_pack (connection, MHD_HTTP_FORBIDDEN, - "{s:s}", - "error", "not enough coins melted"); + return TALER_MINT_reply_json_pack (connection, + MHD_HTTP_FORBIDDEN, + "{s:s}", + "error", + "not enough coins melted"); } if (GNUNET_OK != TALER_MINT_DB_commit (db_conn)) @@ -771,10 +789,11 @@ refresh_send_commit_response (struct MHD_Connection *connection, body.noreveal_index = htons (refresh_session->noreveal_index); sig_json = sign_as_json (&body.purpose); GNUNET_assert (NULL != sig_json); - return request_send_json_pack (connection, MHD_HTTP_OK, - "{s:i, s:o}", - "noreveal_index", (int) refresh_session->noreveal_index, - "signature", sig_json); + return TALER_MINT_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:i, s:o}", + "noreveal_index", (int) refresh_session->noreveal_index, + "signature", sig_json); } @@ -1022,9 +1041,11 @@ TALER_MINT_handler_refresh_commit (struct RequestHandler *rh, if (NULL == commit_sig_json) { GNUNET_break (GNUNET_OK == TALER_MINT_DB_rollback (db_conn)); - return request_send_json_pack (connection, MHD_HTTP_BAD_REQUEST, - "{s:s}", - "error", "commit_signature missing"); + return TALER_MINT_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s}", + "error", + "commit_signature missing"); } body.commit_hash = commit_hash; @@ -1106,9 +1127,9 @@ helper_refresh_reveal_send_response (struct MHD_Connection *connection, TALER_JSON_from_data (&ev_sig, sizeof (struct TALER_RSA_Signature))); } - return send_response_json (connection, - root, - MHD_HTTP_OK); + return TALER_MINT_reply_json (connection, + root, + MHD_HTTP_OK); } @@ -1471,10 +1492,11 @@ TALER_MINT_handler_refresh_link (struct RequestHandler *rh, } if (GNUNET_NO == res) { - return request_send_json_pack (connection, - MHD_HTTP_NOT_FOUND, - "{s:s}", - "error", "link data not found (transfer)"); + return TALER_MINT_reply_json_pack (connection, + MHD_HTTP_NOT_FOUND, + "{s:s}", + "error", + "link data not found (transfer)"); } GNUNET_assert (GNUNET_OK == res); @@ -1486,10 +1508,11 @@ TALER_MINT_handler_refresh_link (struct RequestHandler *rh, } if (GNUNET_NO == res) { - return request_send_json_pack (connection, - MHD_HTTP_NOT_FOUND, - "{s:s}", - "error", "link data not found (link)"); + return TALER_MINT_reply_json_pack (connection, + MHD_HTTP_NOT_FOUND, + "{s:s}", + "error", + "link data not found (link)"); } GNUNET_assert (GNUNET_OK == res); json_object_set_new (root, "transfer_pub", @@ -1498,7 +1521,9 @@ TALER_MINT_handler_refresh_link (struct RequestHandler *rh, json_object_set_new (root, "secret_enc", TALER_JSON_from_data (&shared_secret_enc, sizeof (struct SharedSecretEnc))); - return send_response_json (connection, root, MHD_HTTP_OK); + return TALER_MINT_reply_json (connection, + root, + MHD_HTTP_OK); } diff --git a/src/mint/taler-mint-httpd_responses.c b/src/mint/taler-mint-httpd_responses.c new file mode 100644 index 000000000..8f886c3d9 --- /dev/null +++ b/src/mint/taler-mint-httpd_responses.c @@ -0,0 +1,146 @@ +/* + This file is part of TALER + (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, If not, see <http://www.gnu.org/licenses/> +*/ + +/** + * @file taler-mint-httpd_responses.c + * @brief API for generating the various replies of the mint; these + * functions are called TALER_MINT_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 "taler-mint-httpd_responses.h" + + +/** + * Send JSON object as response. Decreases the reference count of the + * JSON object. + * + * @param connection the MHD connection + * @param json the json object + * @param response_code the http response code + * @return MHD result code + */ +int +TALER_MINT_reply_json (struct MHD_Connection *connection, + json_t *json, + unsigned int response_code) +{ + struct MHD_Response *resp; + char *json_str; + int ret; + + json_str = json_dumps (json, JSON_INDENT(2)); + json_decref (json); + resp = MHD_create_response_from_buffer (strlen (json_str), json_str, + MHD_RESPMEM_MUST_FREE); + if (NULL == resp) + return MHD_NO; + (void) MHD_add_response_header (resp, + MHD_HTTP_HEADER_CONTENT_TYPE, + "application/json"); + 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_MINT_reply_json_pack (struct MHD_Connection *connection, + unsigned int response_code, + const char *fmt, + ...) +{ + json_t *json; + va_list argp; + + va_start (argp, fmt); + json = json_vpack_ex (NULL, 0, fmt, argp); + va_end (argp); + if (NULL == json) + return MHD_NO; + return TALER_MINT_reply_json (connection, + json, + response_code); +} + + +/** + * Send a response indicating an invalid argument. + * + * @param connection the MHD connection to use + * @param param_name the parameter that is invalid + * @return a MHD result code + */ +int +TALER_MINT_reply_arg_invalid (struct MHD_Connection *connection, + const char *param_name) +{ + json_t *json; + + json = json_pack ("{ s:s, s:s }", + "error", + "invalid parameter", + "parameter", + param_name); + return TALER_MINT_reply_json (connection, + json, + MHD_HTTP_BAD_REQUEST); +} + + +/** + * Send a response indicating a missing argument. + * + * @param connection the MHD connection to use + * @param param_name the parameter that is missing + * @return a MHD result code + */ +int +TALER_MINT_reply_arg_missing (struct MHD_Connection *connection, + const char *param_name) +{ + json_t *json; + + json = json_pack ("{ s:s, s:s }", + "error", + "missing parameter", + "parameter", + param_name); + return TALER_MINT_reply_json (connection, + json, + MHD_HTTP_BAD_REQUEST); +} + + + + + + + +/* end of taler-mint-httpd_responses.c */ diff --git a/src/mint/taler-mint-httpd_responses.h b/src/mint/taler-mint-httpd_responses.h new file mode 100644 index 000000000..0e48341fd --- /dev/null +++ b/src/mint/taler-mint-httpd_responses.h @@ -0,0 +1,93 @@ +/* + This file is part of TALER + (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, If not, see <http://www.gnu.org/licenses/> +*/ + +/** + * @file taler-mint-httpd_responses.h + * @brief API for generating the various replies of the mint; these + * functions are called TALER_MINT_reply_ and they generate + * and queue MHD response objects for a given connection. + * @author Florian Dold + * @author Benedikt Mueller + * @author Christian Grothoff + */ +#ifndef TALER_MINT_HTTPD_RESPONSES_H +#define TALER_MINT_HTTPD_RESPONSES_H +#include <gnunet/gnunet_util_lib.h> +#include <jansson.h> +#include <microhttpd.h> +#include <libpq-fe.h> +#include <pthread.h> +#include "taler-mint-httpd.h" +#include "taler-mint-httpd_mhd.h" + + +/** + * Send JSON object as response. Decreases the reference count of the + * JSON object. + * + * @param connection the MHD connection + * @param json the json object + * @param response_code the http response code + * @return MHD result code + */ +int +TALER_MINT_reply_json (struct MHD_Connection *connection, + 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_MINT_reply_json_pack (struct MHD_Connection *connection, + unsigned int response_code, + const char *fmt, + ...); + + +/** + * Send a response indicating an invalid argument. + * + * @param connection the MHD connection to use + * @param param_name the parameter that is invalid + * @return MHD result code + */ +int +TALER_MINT_reply_arg_invalid (struct MHD_Connection *connection, + const char *param_name); + + +/** + * Send a response indicating a missing argument. + * + * @param connection the MHD connection to use + * @param param_name the parameter that is missing + * @return a MHD result code + */ +int +TALER_MINT_reply_arg_missing (struct MHD_Connection *connection, + const char *param_name); + + +#endif diff --git a/src/mint/taler-mint-httpd_withdraw.c b/src/mint/taler-mint-httpd_withdraw.c index 22024e80e..cc0de7f6f 100644 --- a/src/mint/taler-mint-httpd_withdraw.c +++ b/src/mint/taler-mint-httpd_withdraw.c @@ -31,10 +31,11 @@ #include "taler_signatures.h" #include "taler_rsa.h" #include "taler_json_lib.h" -#include "taler-mint-httpd_json.h" +#include "taler-mint-httpd_parsing.h" #include "taler-mint-httpd_keys.h" #include "taler-mint-httpd_mhd.h" #include "taler-mint-httpd_withdraw.h" +#include "taler-mint-httpd_responses.h" /** @@ -135,14 +136,11 @@ TALER_MINT_handler_withdraw_status (struct RequestHandler *rh, &reserve_pub, &reserve); if (GNUNET_SYSERR == res) - return TALER_MINT_helper_send_json_pack (rh, - connection, - connection_cls, - 0 /* no caching */, - MHD_HTTP_NOT_FOUND, - "{s:s}", - "error", - "Reserve not found"); + return TALER_MINT_reply_json_pack (connection, + MHD_HTTP_NOT_FOUND, + "{s:s}", + "error", + "Reserve not found"); if (GNUNET_OK != res) { // FIXME: return 'internal error'? @@ -178,9 +176,9 @@ TALER_MINT_handler_withdraw_status (struct RequestHandler *rh, sig_to_json (&reserve.status_sig_purpose, &reserve.status_sig)); - return send_response_json (connection, - json, - MHD_HTTP_OK); + return TALER_MINT_reply_json (connection, + json, + MHD_HTTP_OK); } @@ -200,9 +198,9 @@ helper_withdraw_sign_send_reply (struct MHD_Connection *connection, json_object_set_new (root, "ev_sig", TALER_JSON_from_data (&collectable->ev_sig, sizeof (struct TALER_RSA_Signature))); - return send_response_json (connection, - root, - MHD_HTTP_OK); + return TALER_MINT_reply_json (connection, + root, + MHD_HTTP_OK); } @@ -317,10 +315,11 @@ TALER_MINT_handler_withdraw_sign (struct RequestHandler *rh, return MHD_NO; } if (GNUNET_NO == res) - return request_send_json_pack (connection, - MHD_HTTP_NOT_FOUND, - "{s:s}", - "error", "Reserve not found"); + return TALER_MINT_reply_json_pack (connection, + MHD_HTTP_NOT_FOUND, + "{s:s}", + "error", + "Reserve not found"); // fill out all the missing info in the request before // we can check the signature on the request @@ -334,19 +333,21 @@ TALER_MINT_handler_withdraw_sign (struct RequestHandler *rh, &wsrd.purpose, &wsrd.sig, &wsrd.reserve_pub)) - return request_send_json_pack (connection, - MHD_HTTP_UNAUTHORIZED, - "{s:s}", - "error", "Invalid Signature"); + return TALER_MINT_reply_json_pack (connection, + MHD_HTTP_UNAUTHORIZED, + "{s:s}", + "error", "Invalid Signature"); key_state = TALER_MINT_key_state_acquire (); dki = TALER_MINT_get_denom_key (key_state, &wsrd.denomination_pub); TALER_MINT_key_state_release (key_state); if (NULL == dki) - return request_send_json_pack (connection, MHD_HTTP_NOT_FOUND, - "{s:s}", - "error", "Denomination not found"); + return TALER_MINT_reply_json_pack (connection, + MHD_HTTP_NOT_FOUND, + "{s:s}", + "error", + "Denomination not found"); amount_required = TALER_amount_ntoh (dki->issue.value); amount_required = TALER_amount_add (amount_required, @@ -354,14 +355,16 @@ TALER_MINT_handler_withdraw_sign (struct RequestHandler *rh, if (0 < TALER_amount_cmp (amount_required, TALER_amount_ntoh (reserve.balance))) - return request_send_json_pack (connection, - MHD_HTTP_PAYMENT_REQUIRED, - "{s:s}", - "error", "Insufficient funds"); - if (GNUNET_OK != TALER_RSA_sign (dki->denom_priv, - &wsrd.coin_envelope, - sizeof (struct TALER_RSA_BlindedSignaturePurpose), - &ev_sig)) + return TALER_MINT_reply_json_pack (connection, + MHD_HTTP_PAYMENT_REQUIRED, + "{s:s}", + "error", + "Insufficient funds"); + if (GNUNET_OK != + TALER_RSA_sign (dki->denom_priv, + &wsrd.coin_envelope, + sizeof (struct TALER_RSA_BlindedSignaturePurpose), + &ev_sig)) { // FIXME: return 'internal error' GNUNET_break (0); |