From a2a5f429159a5be2a453dcc7dacf30e7c0f9e963 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 23 Nov 2019 10:48:05 +0100 Subject: start with libtalermhd --- src/include/Makefile.am | 1 + src/include/gauger.h | 2 +- src/include/taler_mhd_lib.h | 156 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 src/include/taler_mhd_lib.h (limited to 'src/include') 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_mhd_lib.h b/src/include/taler_mhd_lib.h new file mode 100644 index 000000000..553960909 --- /dev/null +++ b/src/include/taler_mhd_lib.h @@ -0,0 +1,156 @@ +/* + 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 +*/ + +/** + * @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 +#include +#include +#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); + + +/** + * 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); + + +#endif -- cgit v1.2.3 From fef8a57fae513259fd0b08e430b04d3b59d20210 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 23 Nov 2019 11:02:34 +0100 Subject: add parsing API to new libtalermhd --- src/include/taler_mhd_lib.h | 108 ++++++++++++++++ src/mhd/Makefile.am | 3 +- src/mhd/mhd_parsing.c | 294 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 404 insertions(+), 1 deletion(-) create mode 100644 src/mhd/mhd_parsing.c (limited to 'src/include') diff --git a/src/include/taler_mhd_lib.h b/src/include/taler_mhd_lib.h index 553960909..d126d0aee 100644 --- a/src/include/taler_mhd_lib.h +++ b/src/include/taler_mhd_lib.h @@ -24,6 +24,7 @@ #ifndef TALER_MHD_LIB_H #define TALER_MHD_LIB_H #include +#include #include #include #include "taler_error_codes.h" @@ -153,4 +154,111 @@ int TALER_MHD_reply_request_too_large (struct MHD_Connection *connection); +/** + * 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); + + #endif diff --git a/src/mhd/Makefile.am b/src/mhd/Makefile.am index 2c6d464f1..ed0c88417 100644 --- a/src/mhd/Makefile.am +++ b/src/mhd/Makefile.am @@ -10,7 +10,8 @@ lib_LTLIBRARIES = \ libtalermhd.la libtalermhd_la_SOURCES = \ - mhd_responses.c + mhd_parsing.c \ + mhd_responses.c libtalermhd_la_LDFLAGS = \ -version-info 0:0:0 \ -export-dynamic -no-undefined diff --git a/src/mhd/mhd_parsing.c b/src/mhd/mhd_parsing.c new file mode 100644 index 000000000..0b070ffe5 --- /dev/null +++ b/src/mhd/mhd_parsing.c @@ -0,0 +1,294 @@ +/* + 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 +*/ +/** + * @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 +#include +#include "taler_json_lib.h" +#include "taler_mhd_lib.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 + * #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) +{ + 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 == + 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 == + TALER_MHD_reply_request_too_large + (connection)) ? GNUNET_SYSERR : GNUNET_NO; + case GNUNET_JSON_PR_JSON_INVALID: + return (MHD_YES == + 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); + 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 + * #TALER_MHD_post_json(), to be cleaned up + */ +void +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); +} + + +/** + * 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_MHD_parse_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_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + 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 == + TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + 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 +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; + 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 = ""; + ret = (MHD_YES == + 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; + } + 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 +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; + 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 == + 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; + } + ret = GNUNET_JSON_parse (root, + spec, + &error_json_name, + &error_line); + if (GNUNET_SYSERR == ret) + { + if (NULL == error_json_name) + error_json_name = ""; + ret = (MHD_YES == + 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; + } + return GNUNET_YES; +} + + +/* end of mhd_parsing.c */ -- cgit v1.2.3 From 0c85d195f8c0fe8363ae234fe962636fca8a77ea Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 23 Nov 2019 11:48:35 +0100 Subject: add common setup logic to libtalermhd --- src/include/taler_mhd_lib.h | 79 +++++++++++- src/mhd/Makefile.am | 1 + src/mhd/mhd_config.c | 287 ++++++++++++++++++++++++++++++++++++++++++++ src/mhd/mhd_responses.c | 91 ++++++++++++++ 4 files changed, 457 insertions(+), 1 deletion(-) create mode 100644 src/mhd/mhd_config.c (limited to 'src/include') diff --git a/src/include/taler_mhd_lib.h b/src/include/taler_mhd_lib.h index d126d0aee..979f83854 100644 --- a/src/include/taler_mhd_lib.h +++ b/src/include/taler_mhd_lib.h @@ -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 */ - /** * @file taler_mhd_lib.h * @brief API for generating MHD replies @@ -154,6 +153,39 @@ 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 @@ -261,4 +293,49 @@ TALER_MHD_parse_request_arg_data (struct MHD_Connection *connection, 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); + + #endif diff --git a/src/mhd/Makefile.am b/src/mhd/Makefile.am index ed0c88417..cc4c70735 100644 --- a/src/mhd/Makefile.am +++ b/src/mhd/Makefile.am @@ -10,6 +10,7 @@ lib_LTLIBRARIES = \ libtalermhd.la libtalermhd_la_SOURCES = \ + mhd_config.c \ mhd_parsing.c \ mhd_responses.c libtalermhd_la_LDFLAGS = \ diff --git a/src/mhd/mhd_config.c b/src/mhd/mhd_config.c new file mode 100644 index 000000000..afaceae40 --- /dev/null +++ b/src/mhd/mhd_config.c @@ -0,0 +1,287 @@ +/* + 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 +*/ +/** + * @file mhd_config.c + * @brief functions to configure and setup MHD + * @author Florian Dold + * @author Benedikt Mueller + * @author Christian Grothoff + */ +#include "platform.h" +#include +#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; +} diff --git a/src/mhd/mhd_responses.c b/src/mhd/mhd_responses.c index 24d55bfac..223381f3d 100644 --- a/src/mhd/mhd_responses.c +++ b/src/mhd/mhd_responses.c @@ -316,4 +316,95 @@ 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) +{ + 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; + } + TEH_RESPONSE_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 */ -- cgit v1.2.3 From c693ec4a3ea797618bee867244f8affe034028b9 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 23 Nov 2019 17:48:45 +0100 Subject: fix warnings --- src/include/taler_mhd_lib.h | 2 +- src/mhd/mhd_responses.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/include') diff --git a/src/include/taler_mhd_lib.h b/src/include/taler_mhd_lib.h index 979f83854..17783f1c4 100644 --- a/src/include/taler_mhd_lib.h +++ b/src/include/taler_mhd_lib.h @@ -183,7 +183,7 @@ TALER_MHD_reply_static (struct MHD_Connection *connection, unsigned int http_status, const char *mime_type, const char *body, - size_t *body_size); + size_t body_size); /** diff --git a/src/mhd/mhd_responses.c b/src/mhd/mhd_responses.c index 223381f3d..e1609d996 100644 --- a/src/mhd/mhd_responses.c +++ b/src/mhd/mhd_responses.c @@ -380,7 +380,7 @@ TALER_MHD_reply_static (struct MHD_Connection *connection, unsigned int http_status, const char *mime_type, const char *body, - size_t *body_size) + size_t body_size) { struct MHD_Response *response; int ret; @@ -393,7 +393,7 @@ TALER_MHD_reply_static (struct MHD_Connection *connection, GNUNET_break (0); return MHD_NO; } - TEH_RESPONSE_add_global_headers (response); + TALER_MHD_add_global_headers (response); if (NULL != mime_type) GNUNET_break (MHD_YES == MHD_add_response_header (response, -- cgit v1.2.3 From 51e54bbaa18397f599e5078153671c98c719c695 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 23 Nov 2019 21:53:14 +0100 Subject: use FORBIDDEN, never UNAUTHORIZED --- src/include/taler_error_codes.h | 4 ++-- src/lib/test_exchange_api_twisted.c | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'src/include') diff --git a/src/include/taler_error_codes.h b/src/include/taler_error_codes.h index 28ee64fed..a2a9bcc46 100644 --- a/src/include/taler_error_codes.h +++ b/src/include/taler_error_codes.h @@ -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, @@ -1905,7 +1905,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, diff --git a/src/lib/test_exchange_api_twisted.c b/src/lib/test_exchange_api_twisted.c index 739669b97..968b7e626 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 */ - /** - * @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 @@ -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"), -- cgit v1.2.3 From 7aae6c90452c1e9bcae78a5e948f381c1165010a Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 23 Nov 2019 22:21:47 +0100 Subject: use CONFLICT for double spending to distinguish properly from FORBIDDEN for bad signatures --- src/auditor/Makefile.am | 4 +- src/auditor/taler-auditor-httpd.c | 8 +- .../taler-auditor-httpd_deposit-confirmation.c | 52 ++- src/auditor/taler-auditor-httpd_exchanges.c | 18 +- src/auditor/taler-auditor-httpd_parsing.c | 284 ------------ src/auditor/taler-auditor-httpd_parsing.h | 139 ------ src/auditor/taler-auditor-httpd_responses.c | 481 --------------------- src/auditor/taler-auditor-httpd_responses.h | 245 ----------- src/exchange/taler-exchange-httpd_refresh_melt.c | 2 +- .../taler-exchange-httpd_reserve_withdraw.c | 2 +- src/exchange/taler-exchange-httpd_responses.c | 2 +- src/include/taler_error_codes.h | 6 +- src/lib/auditor_api_deposit_confirmation.c | 2 +- src/lib/exchange_api_deposit.c | 4 +- src/lib/exchange_api_payback.c | 4 +- src/lib/exchange_api_refresh.c | 16 +- src/lib/exchange_api_refund.c | 2 +- src/lib/exchange_api_reserve.c | 6 +- src/lib/exchange_api_track_transaction.c | 2 +- src/lib/exchange_api_track_transfer.c | 2 +- 20 files changed, 71 insertions(+), 1210 deletions(-) delete mode 100644 src/auditor/taler-auditor-httpd_parsing.c delete mode 100644 src/auditor/taler-auditor-httpd_parsing.h delete mode 100644 src/auditor/taler-auditor-httpd_responses.c delete mode 100644 src/auditor/taler-auditor-httpd_responses.h (limited to 'src/include') diff --git a/src/auditor/Makefile.am b/src/auditor/Makefile.am index 6d0c81582..a1bb4d247 100644 --- a/src/auditor/Makefile.am +++ b/src/auditor/Makefile.am @@ -52,9 +52,7 @@ 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 \ diff --git a/src/auditor/taler-auditor-httpd.c b/src/auditor/taler-auditor-httpd.c index fa4f572ec..bf1e7ac71 100644 --- a/src/auditor/taler-auditor-httpd.c +++ b/src/auditor/taler-auditor-httpd.c @@ -31,7 +31,6 @@ #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" @@ -292,7 +291,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; } @@ -559,12 +558,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, diff --git a/src/auditor/taler-auditor-httpd_deposit-confirmation.c b/src/auditor/taler-auditor-httpd_deposit-confirmation.c index 2b73a910a..23ea14a9f 100644 --- a/src/auditor/taler-auditor-httpd_deposit-confirmation.c +++ b/src/auditor/taler-auditor-httpd_deposit-confirmation.c @@ -27,10 +27,10 @@ #include #include #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 +43,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 +74,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 +113,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 +159,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 +192,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 +254,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..27b339636 100644 --- a/src/auditor/taler-auditor-httpd_exchanges.c +++ b/src/auditor/taler-auditor-httpd_exchanges.c @@ -25,10 +25,10 @@ #include #include #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 +43,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 +108,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 +150,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_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 -*/ - -/** - * @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 -#include -#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 = ""; - 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 = ""; - 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 -*/ -/** - * @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 -#include -#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 2f78fb0f5..000000000 --- a/src/auditor/taler-auditor-httpd_responses.c +++ /dev/null @@ -1,481 +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 -*/ -/** - * @file taler-auditor-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 -#include "taler_mhd_lib.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 -*/ - -/** - * @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 -#include -#include -#include -#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/taler-exchange-httpd_refresh_melt.c b/src/exchange/taler-exchange-httpd_refresh_melt.c index 71f1a6142..8fbb58513 100644 --- a/src/exchange/taler-exchange-httpd_refresh_melt.c +++ b/src/exchange/taler-exchange-httpd_refresh_melt.c @@ -66,7 +66,7 @@ reply_refresh_melt_insufficient_funds (struct MHD_Connection *connection, TALER_EC_REFRESH_MELT_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS, "Failed to compile transaction history"); return TALER_MHD_reply_json_pack (connection, - MHD_HTTP_FORBIDDEN, + MHD_HTTP_CONFLICT, "{s:s, s:I, s:o, s:o, s:o, s:o, s:o}", "error", "insufficient funds", diff --git a/src/exchange/taler-exchange-httpd_reserve_withdraw.c b/src/exchange/taler-exchange-httpd_reserve_withdraw.c index 2b4d2b93d..8b59817a7 100644 --- a/src/exchange/taler-exchange-httpd_reserve_withdraw.c +++ b/src/exchange/taler-exchange-httpd_reserve_withdraw.c @@ -72,7 +72,7 @@ reply_reserve_withdraw_insufficient_funds (struct MHD_Connection *connection, json_balance = TALER_JSON_from_amount (&balance); return TALER_MHD_reply_json_pack (connection, - MHD_HTTP_FORBIDDEN, + MHD_HTTP_CONFLICT, "{s:s, s:I, s:o, s:o}", "error", "Insufficient funds", "code", diff --git a/src/exchange/taler-exchange-httpd_responses.c b/src/exchange/taler-exchange-httpd_responses.c index f051cd2e5..97b1e8f1e 100644 --- a/src/exchange/taler-exchange-httpd_responses.c +++ b/src/exchange/taler-exchange-httpd_responses.c @@ -880,7 +880,7 @@ TEH_RESPONSE_reply_coin_insufficient_funds (struct MHD_Connection *connection, TALER_EC_COIN_HISTORY_DB_ERROR_INSUFFICIENT_FUNDS, "failed to convert transaction history to JSON"); return TALER_MHD_reply_json_pack (connection, - MHD_HTTP_FORBIDDEN, + MHD_HTTP_CONFLICT, "{s:s, s:I, s:o}", "error", "insufficient funds", "code", (json_int_t) ec, diff --git a/src/include/taler_error_codes.h b/src/include/taler_error_codes.h index a2a9bcc46..871ec2bfe 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, 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_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 */ -- cgit v1.2.3 From 287a8dec9b3d6d2ee77a55fec4afff45f2cb826d Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 24 Nov 2019 17:15:01 +0100 Subject: add another convenience function to libtalermhd --- src/include/taler_error_codes.h | 1 + src/include/taler_mhd_lib.h | 52 +++++++++++++++++++ src/mhd/mhd_config.c | 109 ++++++++++++++++++++++++++++++++++++++++ src/mhd/mhd_responses.c | 91 +++++++++++++++++++++++++++++++++ 4 files changed, 253 insertions(+) (limited to 'src/include') diff --git a/src/include/taler_error_codes.h b/src/include/taler_error_codes.h index 871ec2bfe..55cdbacbd 100644 --- a/src/include/taler_error_codes.h +++ b/src/include/taler_error_codes.h @@ -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, diff --git a/src/include/taler_mhd_lib.h b/src/include/taler_mhd_lib.h index 17783f1c4..cdbc8d290 100644 --- a/src/include/taler_mhd_lib.h +++ b/src/include/taler_mhd_lib.h @@ -143,6 +143,40 @@ TALER_MHD_reply_with_error (struct MHD_Connection *connection, 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. * @@ -338,4 +372,22 @@ 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/mhd/mhd_config.c b/src/mhd/mhd_config.c index afaceae40..d4b0e9795 100644 --- a/src/mhd/mhd_config.c +++ b/src/mhd/mhd_config.c @@ -285,3 +285,112 @@ TALER_MHD_open_unix_path (const char *unix_path, 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/mhd/mhd_responses.c b/src/mhd/mhd_responses.c index e1609d996..3642e7d54 100644 --- a/src/mhd/mhd_responses.c +++ b/src/mhd/mhd_responses.c @@ -151,6 +151,43 @@ TALER_MHD_body_compress (void **buf, } +/** + * 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. * @@ -267,6 +304,60 @@ TALER_MHD_reply_json_pack (struct MHD_Connection *connection, } +/** + * 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. * -- cgit v1.2.3 From b7a5af7fd4ea302df013ad492d8a420efca5864c Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 24 Nov 2019 17:20:13 +0100 Subject: another sync code --- src/include/taler_error_codes.h | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src/include') diff --git a/src/include/taler_error_codes.h b/src/include/taler_error_codes.h index 55cdbacbd..05bd9ce91 100644 --- a/src/include/taler_error_codes.h +++ b/src/include/taler_error_codes.h @@ -1852,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, @@ -1967,17 +1967,23 @@ enum TALER_ErrorCode /** * Sync could not store order data in its own database. * This response is provided with HTTP status code - * MHD_HTTP_INTERNAL_ERROR. + * MHD_HTTP_INTERNAL_SERVER_ERROR. */ TALER_EC_SYNC_PAYMENT_CREATE_DB_ERROR = 6015, /** * Sync could not store payment confirmation in its own database. * This response is provided with HTTP status code - * MHD_HTTP_INTERNAL_ERROR. + * MHD_HTTP_INTERNAL_SERVER_ERROR. */ TALER_EC_SYNC_PAYMENT_CONFIRM_DB_ERROR = 6016, + /** + * Sync could check for payment confirmation in its own database. + * This response is provided with HTTP status code + * MHD_HTTP_INTERNAL_SERVER_ERROR. + */ + TALER_EC_SYNC_PAYMENT_CHECK_ORDER_DB_ERROR = 6017, /** * End of error code range. -- cgit v1.2.3 From 70a210ac4db07a28867e23db13c68aecc117810a Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Mon, 25 Nov 2019 01:42:55 +0100 Subject: add another helper --- src/include/taler_json_lib.h | 13 +++++++++++++ src/json/json.c | 29 +++++++++++++++++++++++++++++ src/lib/exchange_api_curl_defaults.c | 1 - 3 files changed, 42 insertions(+), 1 deletion(-) (limited to 'src/include') 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/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/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, -- cgit v1.2.3