exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

taler_mhd_lib.h (41733B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2014-2025 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU Affero General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
     12 
     13   You should have received a copy of the GNU Affero General Public License along with
     14   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file taler_mhd_lib.h
     18  * @brief API for generating MHD replies
     19  * @author Florian Dold
     20  * @author Benedikt Mueller
     21  * @author Christian Grothoff
     22  */
     23 #ifndef TALER_MHD_LIB_H
     24 #define TALER_MHD_LIB_H
     25 
     26 #include <jansson.h>
     27 #include <microhttpd.h>
     28 #include <gnunet/gnunet_json_lib.h>
     29 #include <taler/taler_error_codes.h>
     30 #include <taler/taler_util.h>
     31 
     32 
     33 /**
     34  * Maximum POST request size.
     35  */
     36 #define TALER_MHD_REQUEST_BUFFER_MAX (1024 * 1024 * 16)
     37 
     38 
     39 /**
     40  * Global options for response generation.
     41  */
     42 enum TALER_MHD_GlobalOptions
     43 {
     44 
     45   /**
     46    * Use defaults.
     47    */
     48   TALER_MHD_GO_NONE = 0,
     49 
     50   /**
     51    * Add "Connection: Close" header.
     52    */
     53   TALER_MHD_GO_FORCE_CONNECTION_CLOSE = 1,
     54 
     55   /**
     56    * Disable use of compression, even if the client
     57    * supports it.
     58    */
     59   TALER_MHD_GO_DISABLE_COMPRESSION = 2
     60 
     61 };
     62 
     63 
     64 #if MHD_VERSION < 0x00097701
     65 #define MHD_create_response_from_buffer_static(s, b)            \
     66         MHD_create_response_from_buffer (s,                     \
     67                                          (const char *) b,      \
     68                                          MHD_RESPMEM_PERSISTENT)
     69 #endif
     70 
     71 
     72 /**
     73  * Find out if an MHD connection is using HTTPS (either
     74  * directly or via proxy).
     75  *
     76  * @param connection MHD connection
     77  * @returns #GNUNET_YES if the MHD connection is using https,
     78  *          #GNUNET_NO if the MHD connection is using http,
     79  *          #GNUNET_SYSERR if the connection type couldn't be determined
     80  */
     81 enum GNUNET_GenericReturnValue
     82 TALER_mhd_is_https (struct MHD_Connection *connection);
     83 
     84 
     85 /**
     86  * Convert query argument to @a yna value.
     87  *
     88  * @param connection connection to take query argument from
     89  * @param arg argument to try for
     90  * @param default_val value to assign if the argument is not present
     91  * @param[out] yna value to set
     92  * @return true on success, false if the parameter was malformed
     93  */
     94 bool
     95 TALER_MHD_arg_to_yna (struct MHD_Connection *connection,
     96                       const char *arg,
     97                       enum TALER_EXCHANGE_YesNoAll default_val,
     98                       enum TALER_EXCHANGE_YesNoAll *yna);
     99 
    100 
    101 /**
    102  * Set global options for response generation within libtalermhd.
    103  *
    104  * @param go global options to use
    105  */
    106 void
    107 TALER_MHD_setup (enum TALER_MHD_GlobalOptions go);
    108 
    109 
    110 /**
    111  * Add headers we want to return in every response.  Useful for testing, like
    112  * if we want to always close connections.
    113  *
    114  * @param response response to modify
    115  * @param allow_store set to true to NOT add a "Cache-Control"
    116  *        directive that prevents caches and browsers from storing the data;
    117  *        if false, we set "Cache-Control: no-store" (privacy by default);
    118  *        set to true if the response contains no personal data
    119  */
    120 void
    121 TALER_MHD_add_global_headers (struct MHD_Response *response,
    122                               bool allow_store);
    123 
    124 
    125 /**
    126  * Try to compress a response body.  Updates @a buf and @a buf_size.
    127  *
    128  * @param[in,out] buf pointer to body to compress
    129  * @param[in,out] buf_size pointer to initial size of @a buf
    130  * @return #MHD_YES if @a buf was compressed
    131  */
    132 enum MHD_Result
    133 TALER_MHD_body_compress (void **buf,
    134                          size_t *buf_size);
    135 
    136 
    137 /**
    138  * List of compression types we check for. Larger numeric values
    139  * indicate a preferred algorithm.
    140  */
    141 enum TALER_MHD_CompressionType
    142 {
    143   /**
    144    * Compression is not supported.
    145    */
    146   TALER_MHD_CT_NONE = 0,
    147 
    148   /**
    149    * Deflate compression supported.
    150    */
    151   TALER_MHD_CT_DEFLATE,
    152 
    153   /**
    154    * gzip compression supported.
    155    */
    156   TALER_MHD_CT_GZIP,
    157 
    158   /**
    159    * zstd compression supported.
    160    */
    161   TALER_MHD_CT_ZSTD,
    162 
    163   /**
    164    * End of list marker.
    165    */
    166   TALER_MHD_CT_MAX
    167 };
    168 
    169 
    170 /**
    171  * What type of HTTP compression is supported by the client?
    172  *
    173  * @param connection connection to check
    174  * @param max maximum compression level to check for
    175  * @return #MHD_YES if 'deflate' compression is allowed
    176  */
    177 enum TALER_MHD_CompressionType
    178 TALER_MHD_can_compress (struct MHD_Connection *connection,
    179                         enum TALER_MHD_CompressionType max);
    180 
    181 
    182 /**
    183  * Send JSON object as response.
    184  *
    185  * @param connection the MHD connection
    186  * @param json the json object
    187  * @param response_code the http response code
    188  * @return MHD result code
    189  */
    190 enum MHD_Result
    191 TALER_MHD_reply_json (struct MHD_Connection *connection,
    192                       const json_t *json,
    193                       unsigned int response_code);
    194 
    195 
    196 /**
    197  * Send JSON object as response, and free the @a json
    198  * object.
    199  *
    200  * @param connection the MHD connection
    201  * @param json the json object (freed!)
    202  * @param response_code the http response code
    203  * @return MHD result code
    204  */
    205 enum MHD_Result
    206 TALER_MHD_reply_json_steal (struct MHD_Connection *connection,
    207                             json_t *json,
    208                             unsigned int response_code);
    209 
    210 
    211 /**
    212  * Function to call to handle the request by building a JSON
    213  * reply from varargs.
    214  *
    215  * @param connection the MHD connection to handle
    216  * @param response_code HTTP response code to use
    217  * @param ... varargs of JSON pack specification
    218  * @return MHD result code
    219  */
    220 #define TALER_MHD_REPLY_JSON_PACK(connection,response_code,...) \
    221         TALER_MHD_reply_json_steal (connection, GNUNET_JSON_PACK (__VA_ARGS__), \
    222                                     response_code)
    223 
    224 
    225 /**
    226  * Send a response indicating an error.
    227  *
    228  * @param connection the MHD connection to use
    229  * @param ec error code uniquely identifying the error
    230  * @param http_status HTTP status code to use
    231  * @param detail additional optional detail about the error
    232  * @return a MHD result code
    233  */
    234 enum MHD_Result
    235 TALER_MHD_reply_with_error (struct MHD_Connection *connection,
    236                             unsigned int http_status,
    237                             enum TALER_ErrorCode ec,
    238                             const char *detail);
    239 
    240 
    241 /**
    242  * Send a response indicating an error. The HTTP status code is
    243  * to be derived from the @a ec.
    244  *
    245  * @param connection the MHD connection to use
    246  * @param ec error code uniquely identifying the error
    247  * @param detail additional optional detail about the error
    248  * @return a MHD result code
    249  */
    250 enum MHD_Result
    251 TALER_MHD_reply_with_ec (struct MHD_Connection *connection,
    252                          enum TALER_ErrorCode ec,
    253                          const char *detail);
    254 
    255 
    256 /**
    257  * Produce HTTP "Date:" header.
    258  *
    259  * @param at time to write to @a date
    260  * @param[out] date where to write the header, with
    261  *        at least 128 bytes available space.
    262  */
    263 void
    264 TALER_MHD_get_date_string (struct GNUNET_TIME_Absolute at,
    265                            char date[128]);
    266 
    267 
    268 /**
    269  * Make JSON response object.
    270  *
    271  * @param json the json object
    272  * @return MHD response object
    273  */
    274 struct MHD_Response *
    275 TALER_MHD_make_json (const json_t *json);
    276 
    277 
    278 /**
    279  * Make JSON response object and free @a json.
    280  *
    281  * @param json the json object, freed.
    282  * @return MHD response object
    283  */
    284 struct MHD_Response *
    285 TALER_MHD_make_json_steal (json_t *json);
    286 
    287 
    288 /**
    289  * Make JSON response object.
    290  *
    291  * @param ... varargs
    292  * @return MHD response object
    293  */
    294 #define TALER_MHD_MAKE_JSON_PACK(...) \
    295         TALER_MHD_make_json_steal (GNUNET_JSON_PACK (__VA_ARGS__))
    296 
    297 
    298 /**
    299  * Pack Taler error code @a ec and associated hint into a
    300  * JSON object.
    301  *
    302  * @param ec error code to pack
    303  * @return packer array entries (two!)
    304  */
    305 #define TALER_MHD_PACK_EC(ec) \
    306         GNUNET_JSON_pack_uint64 ("code", ec), \
    307         GNUNET_JSON_pack_string ("hint", TALER_ErrorCode_get_hint (ec))
    308 
    309 /**
    310  * Create a response indicating an internal error.
    311  *
    312  * @param ec error code to return
    313  * @param detail additional optional detail about the error, can be NULL
    314  * @return a MHD response object
    315  */
    316 struct MHD_Response *
    317 TALER_MHD_make_error (enum TALER_ErrorCode ec,
    318                       const char *detail);
    319 
    320 
    321 /**
    322  * Send a response indicating that the request was too big.
    323  *
    324  * @param connection the MHD connection to use
    325  * @return a MHD result code
    326  */
    327 enum MHD_Result
    328 TALER_MHD_reply_request_too_large (struct MHD_Connection *connection);
    329 
    330 
    331 /**
    332  * Function to call to handle the request by sending
    333  * back a redirect to the AGPL source code.
    334  *
    335  * @param connection the MHD connection to handle
    336  * @param url where to redirect for the sources
    337  * @return MHD result code
    338  */
    339 enum MHD_Result
    340 TALER_MHD_reply_agpl (struct MHD_Connection *connection,
    341                       const char *url);
    342 
    343 
    344 /**
    345  * Function to call to handle the request by sending
    346  * back static data.
    347  *
    348  * @param connection the MHD connection to handle
    349  * @param http_status status code to return
    350  * @param mime_type content-type to use
    351  * @param body response payload
    352  * @param body_size number of bytes in @a body
    353  * @return MHD result code
    354  */
    355 enum MHD_Result
    356 TALER_MHD_reply_static (struct MHD_Connection *connection,
    357                         unsigned int http_status,
    358                         const char *mime_type,
    359                         const char *body,
    360                         size_t body_size);
    361 
    362 
    363 /**
    364  * Process a POST request containing a JSON object.  This
    365  * function realizes an MHD POST processor that will
    366  * (incrementally) process JSON data uploaded to the HTTP
    367  * server.  It will store the required state in the
    368  * "connection_cls", which must be cleaned up using
    369  * #TALER_MHD_parse_post_cleanup_callback().
    370  *
    371  * @param connection the MHD connection
    372  * @param con_cls the closure (points to a `struct Buffer *`)
    373  * @param upload_data the POST data
    374  * @param upload_data_size number of bytes in @a upload_data
    375  * @param json the JSON object for a completed request
    376  * @return
    377  *    #GNUNET_YES if json object was parsed or at least
    378  *               may be parsed in the future (call again);
    379  *               `*json` will be NULL if we need to be called again,
    380  *                and non-NULL if we are done.
    381  *    #GNUNET_NO is request incomplete or invalid
    382  *               (error message was generated)
    383  *    #GNUNET_SYSERR on internal error
    384  *               (we could not even queue an error message,
    385  *                close HTTP session with MHD_NO)
    386  */
    387 enum GNUNET_GenericReturnValue
    388 TALER_MHD_parse_post_json (struct MHD_Connection *connection,
    389                            void **con_cls,
    390                            const char *upload_data,
    391                            size_t *upload_data_size,
    392                            json_t **json);
    393 
    394 
    395 /**
    396  * Function called whenever we are done with a request
    397  * to clean up our state.
    398  *
    399  * @param con_cls value as it was left by
    400  *        #TALER_MHD_parse_post_json(), to be cleaned up
    401  */
    402 void
    403 TALER_MHD_parse_post_cleanup_callback (void *con_cls);
    404 
    405 
    406 /**
    407  * Parse JSON object into components based on the given field
    408  * specification.  If parsing fails, we return an HTTP
    409  * status code of 400 (#MHD_HTTP_BAD_REQUEST).
    410  *
    411  * @param connection the connection to send an error response to
    412  * @param root the JSON node to start the navigation at.
    413  * @param spec field specification for the parser
    414  * @return
    415  *    #GNUNET_YES if navigation was successful (caller is responsible
    416  *                for freeing allocated variable-size data using
    417  *                GNUNET_JSON_parse_free() when done)
    418  *    #GNUNET_NO if json is malformed, error response was generated
    419  *    #GNUNET_SYSERR on internal error
    420  */
    421 enum GNUNET_GenericReturnValue
    422 TALER_MHD_parse_json_data (struct MHD_Connection *connection,
    423                            const json_t *root,
    424                            struct GNUNET_JSON_Specification *spec);
    425 
    426 
    427 /**
    428  * Parse JSON object that we (the server!) generated into components based on
    429  * the given field specification.  The difference to
    430  * #TALER_MHD_parse_json_data() is that this function will fail
    431  * with an HTTP failure of 500 (internal server error) in case
    432  * parsing fails, instead of blaming it on the client with a
    433  * 400 (#MHD_HTTP_BAD_REQUEST).
    434  *
    435  * @param connection the connection to send an error response to
    436  * @param root the JSON node to start the navigation at.
    437  * @param spec field specification for the parser
    438  * @return
    439  *    #GNUNET_YES if navigation was successful (caller is responsible
    440  *                for freeing allocated variable-size data using
    441  *                GNUNET_JSON_parse_free() when done)
    442  *    #GNUNET_NO if json is malformed, error response was generated
    443  *    #GNUNET_SYSERR on internal error
    444  */
    445 enum GNUNET_GenericReturnValue
    446 TALER_MHD_parse_internal_json_data (struct MHD_Connection *connection,
    447                                     const json_t *root,
    448                                     struct GNUNET_JSON_Specification *spec);
    449 
    450 
    451 /**
    452  * Parse JSON array into components based on the given field
    453  * specification.  Generates error response on parse errors.
    454  *
    455  * @param connection the connection to send an error response to
    456  * @param root the JSON node to start the navigation at.
    457  * @param[in,out] spec field specification for the parser
    458  * @param ... -1-terminated list of array offsets of type 'int'
    459  * @return
    460  *    #GNUNET_YES if navigation was successful (caller is responsible
    461  *                for freeing allocated variable-size data using
    462  *                GNUNET_JSON_parse_free() when done)
    463  *    #GNUNET_NO if json is malformed, error response was generated
    464  *    #GNUNET_SYSERR on internal error
    465  */
    466 enum GNUNET_GenericReturnValue
    467 TALER_MHD_parse_json_array (struct MHD_Connection *connection,
    468                             const json_t *root,
    469                             struct GNUNET_JSON_Specification *spec,
    470                             ...);
    471 
    472 
    473 /**
    474  * Extract optional relative time argument from request.
    475  *
    476  * @param connection the MHD connection
    477  * @param label name of the argument to parse
    478  * @param[out] duration set to #GNUNET_TIME_UNIT_ZERO if there was no duration argument given
    479  * @return #GNUNET_OK on success, #GNUNET_NO if an
    480  *     error was returned on @a connection (caller should return #MHD_YES) and
    481  *     #GNUNET_SYSERR if we failed to return an error (caller should return #MHD_NO)
    482  */
    483 enum GNUNET_GenericReturnValue
    484 TALER_MHD_parse_request_arg_rel_time (struct MHD_Connection *connection,
    485                                       const char *label,
    486                                       struct GNUNET_TIME_Relative *duration);
    487 
    488 
    489 /**
    490  * Extract optional relative time argument from request.
    491  * Macro that *returns* #MHD_YES/#MHD_NO if the @a label
    492  * argument existed but failed to parse.
    493  *
    494  * @param connection the MHD connection
    495  * @param label label to check for
    496  * @param[out] duration set to #GNUNET_TIME_UNIT_ZERO if there was no duration given
    497  */
    498 #define TALER_MHD_parse_request_rel_time(connection,label,duration)   \
    499         do {                                                          \
    500           switch (TALER_MHD_parse_request_arg_rel_time (connection,   \
    501                                                         label,        \
    502                                                         duration))  \
    503           {                      \
    504           case GNUNET_SYSERR:    \
    505             GNUNET_break (0);    \
    506             return MHD_NO;       \
    507           case GNUNET_NO:        \
    508             GNUNET_break_op (0); \
    509             return MHD_YES;      \
    510           case GNUNET_OK:        \
    511             break;               \
    512           }                      \
    513         } while (0)
    514 
    515 
    516 /**
    517  * Extract optional "timeout_ms" argument from request.
    518  *
    519  * @param connection the MHD connection
    520  * @param[out] expiration set to #GNUNET_TIME_UNIT_ZERO_ABS if there was no timeout,
    521  *         the current time plus the value given under "timeout_ms" otherwise
    522  * @return #GNUNET_OK on success, #GNUNET_NO if an
    523  *     error was returned on @a connection (caller should return #MHD_YES) and
    524  *     #GNUNET_SYSERR if we failed to return an error (caller should return #MHD_NO)
    525  */
    526 enum GNUNET_GenericReturnValue
    527 TALER_MHD_parse_request_arg_timeout (struct MHD_Connection *connection,
    528                                      struct GNUNET_TIME_Absolute *expiration);
    529 
    530 
    531 /**
    532  * Extract optional "timeout_ms" argument from request.
    533  * Macro that *returns* #MHD_YES/#MHD_NO if the "timeout_ms"
    534  * argument existed but failed to parse.
    535  *
    536  * @param connection the MHD connection
    537  * @param[out] expiration set to #GNUNET_TIME_UNIT_ZERO_ABS if there was no timeout,
    538  *         the current time plus the value given under "timeout_ms" otherwise
    539  */
    540 #define TALER_MHD_parse_request_timeout(connection,expiration) \
    541         do {                                                         \
    542           switch (TALER_MHD_parse_request_arg_timeout (connection,   \
    543                                                        expiration))  \
    544           {                      \
    545           case GNUNET_SYSERR:    \
    546             GNUNET_break (0);    \
    547             return MHD_NO;       \
    548           case GNUNET_NO:        \
    549             GNUNET_break_op (0); \
    550             return MHD_YES;      \
    551           case GNUNET_OK:        \
    552             break;               \
    553           }                      \
    554         } while (0)
    555 
    556 
    557 /**
    558  * Extract optional timestamp argument from request.
    559  *
    560  * @param connection the MHD connection
    561  * @param fname name of the argument to parse
    562  * @param[out] ts set to #GNUNET_TIME_UNIT_ZERO_TS if there was no timestamp
    563  * @return #GNUNET_OK on success, #GNUNET_NO if an
    564  *     error was returned on @a connection (caller should return #MHD_YES) and
    565  *     #GNUNET_SYSERR if we failed to return an error (caller should return #MHD_NO)
    566  */
    567 enum GNUNET_GenericReturnValue
    568 TALER_MHD_parse_request_arg_timestamp (struct MHD_Connection *connection,
    569                                        const char *fname,
    570                                        struct GNUNET_TIME_Timestamp *ts);
    571 
    572 
    573 /**
    574  * Extract optional timestamp argument from request.
    575  * Macro that *returns* #MHD_YES/#MHD_NO if the timestamp
    576  * argument existed but failed to parse.
    577  *
    578  * @param connection the MHD connection
    579  * @param fname name of the argument
    580  * @param[out] ts set to #GNUNET_TIME_UNIT_ZERO_TS if there was no timestamp
    581  */
    582 #define TALER_MHD_parse_request_timestamp(connection,fname,ts)  \
    583         do {                                                         \
    584           switch (TALER_MHD_parse_request_arg_timestamp (connection,   \
    585                                                          fname, \
    586                                                          ts))   \
    587           {                      \
    588           case GNUNET_SYSERR:    \
    589             GNUNET_break (0);    \
    590             return MHD_NO;       \
    591           case GNUNET_NO:        \
    592             GNUNET_break_op (0); \
    593             return MHD_YES;      \
    594           case GNUNET_OK:        \
    595             break;               \
    596           }                      \
    597         } while (0)
    598 
    599 
    600 /**
    601  * Extract optional "yes/no/all" argument from request.
    602  * Macro that *returns* #MHD_YES/#MHD_NO if the
    603  * argument existed but failed to parse.
    604  *
    605  * @param connection the MHD connection
    606  * @param name name of the query parameter to parse
    607  * @param def default value to set if absent
    608  * @param[out] ret set to the yes/no/all value
    609  */
    610 #define TALER_MHD_parse_request_yna(connection,name,def,ret) \
    611         do {                                        \
    612           if (! (TALER_MHD_arg_to_yna (connection,      \
    613                                        name,            \
    614                                        def,             \
    615                                        ret)) )          \
    616           {                                         \
    617             GNUNET_break_op (0);                    \
    618             return TALER_MHD_reply_with_error (     \
    619               connection,                           \
    620               MHD_HTTP_BAD_REQUEST,                 \
    621               TALER_EC_GENERIC_PARAMETER_MALFORMED, \
    622               name);                                \
    623           }                                         \
    624         } while (0)
    625 
    626 /**
    627  * Extract optional numeric limit argument from request.
    628  *
    629  * @param connection the MHD connection
    630  * @param name name of the query parameter
    631  * @param[out] off set to the offset, unchanged if the
    632  *             option was not given
    633  * @return #GNUNET_OK on success,
    634  *         #GNUNET_NO if an error was returned on @a connection (caller should return #MHD_YES) and
    635  *     #GNUNET_SYSERR if we failed to return an error (caller should return #MHD_NO)
    636  */
    637 enum GNUNET_GenericReturnValue
    638 TALER_MHD_parse_request_arg_number (struct MHD_Connection *connection,
    639                                     const char *name,
    640                                     uint64_t *off);
    641 
    642 
    643 /**
    644  * Extract optional numeric argument from request.
    645  * Macro that *returns* #MHD_YES/#MHD_NO if the
    646  * requested argument existed but failed to parse.
    647  *
    648  * @param connection the MHD connection
    649  * @param name name of the argument to parse
    650  * @param[out] off set to the given numeric value,
    651  *    unchanged if value was not specified
    652  */
    653 #define TALER_MHD_parse_request_number(connection,name,off)  \
    654         do {                                                         \
    655           switch (TALER_MHD_parse_request_arg_number (connection,   \
    656                                                       name, \
    657                                                       off))  \
    658           {                      \
    659           case GNUNET_SYSERR:    \
    660             GNUNET_break (0);    \
    661             return MHD_NO;       \
    662           case GNUNET_NO:        \
    663             GNUNET_break_op (0); \
    664             return MHD_YES;      \
    665           case GNUNET_OK:        \
    666             break;               \
    667           }                      \
    668         } while (0)
    669 
    670 
    671 /**
    672  * Extract optional signed numeric limit argument from request.
    673  *
    674  * @param connection the MHD connection
    675  * @param name name of the query parameter
    676  * @param[out] val set to the signed value, unchanged if the
    677  *             option was not given
    678  * @return #GNUNET_OK on success,
    679  *         #GNUNET_NO if an error was returned on @a connection (caller should return #MHD_YES) and
    680  *     #GNUNET_SYSERR if we failed to return an error (caller should return #MHD_NO)
    681  */
    682 enum GNUNET_GenericReturnValue
    683 TALER_MHD_parse_request_arg_snumber (struct MHD_Connection *connection,
    684                                      const char *name,
    685                                      int64_t *val);
    686 
    687 
    688 /**
    689  * Extract optional numeric argument from request.
    690  * Macro that *returns* #MHD_YES/#MHD_NO if the
    691  * requested argument existed but failed to parse.
    692  *
    693  * @param connection the MHD connection
    694  * @param name name of the argument to parse
    695  * @param[out] val set to the given numeric value,
    696  *    unchanged if value was not specified
    697  */
    698 #define TALER_MHD_parse_request_snumber(connection,name,val)  \
    699         do {                                                         \
    700           switch (TALER_MHD_parse_request_arg_snumber (connection,   \
    701                                                        name, \
    702                                                        val))  \
    703           {                      \
    704           case GNUNET_SYSERR:    \
    705             GNUNET_break (0);    \
    706             return MHD_NO;       \
    707           case GNUNET_NO:        \
    708             GNUNET_break_op (0); \
    709             return MHD_YES;      \
    710           case GNUNET_OK:        \
    711             break;               \
    712           }                      \
    713         } while (0)
    714 
    715 
    716 /**
    717  * Extract optional amount argument from request.
    718  *
    719  * @param connection the MHD connection
    720  * @param name name of the query parameter
    721  * @param[out] val set to the amount, unchanged if the
    722  *             option was not given
    723  * @return #GNUNET_OK on success,
    724  *         #GNUNET_NO if an error was returned on @a connection (caller should return #MHD_YES) and
    725  *     #GNUNET_SYSERR if we failed to return an error (caller should return #MHD_NO)
    726  */
    727 enum GNUNET_GenericReturnValue
    728 TALER_MHD_parse_request_arg_amount (struct MHD_Connection *connection,
    729                                     const char *name,
    730                                     struct TALER_Amount *val);
    731 
    732 
    733 /**
    734  * Extract optional amount argument from request.  Macro that *returns*
    735  * #MHD_YES/#MHD_NO if the requested argument existed but failed to parse.
    736  *
    737  * @param connection the MHD connection
    738  * @param name name of the argument to parse
    739  * @param[out] val set to the given amount,
    740  *    unchanged if value was not specified
    741  */
    742 #define TALER_MHD_parse_request_amount(connection,name,val)  \
    743         do {                                                         \
    744           switch (TALER_MHD_parse_request_arg_amount (connection,   \
    745                                                       name, \
    746                                                       val))  \
    747           {                      \
    748           case GNUNET_SYSERR:    \
    749             GNUNET_break (0);    \
    750             return MHD_NO;       \
    751           case GNUNET_NO:        \
    752             GNUNET_break_op (0); \
    753             return MHD_YES;      \
    754           case GNUNET_OK:        \
    755             break;               \
    756           }                      \
    757         } while (0)
    758 
    759 
    760 /**
    761  * Extract fixed-size base32crockford encoded data from request argument.
    762  *
    763  * Queues an error response to the connection if the parameter is missing or
    764  * invalid.
    765  *
    766  * @param connection the MHD connection
    767  * @param param_name the name of the parameter with the key
    768  * @param[out] out_data pointer to store the result
    769  * @param out_size expected size of @a out_data
    770  * @param[out] present set to true if argument was found
    771  * @return
    772  *   #GNUNET_YES if the the argument is present
    773  *   #GNUNET_NO if the argument is malformed
    774  *   #GNUNET_SYSERR on internal error (error response could not be sent)
    775  */
    776 enum GNUNET_GenericReturnValue
    777 TALER_MHD_parse_request_arg_data (struct MHD_Connection *connection,
    778                                   const char *param_name,
    779                                   void *out_data,
    780                                   size_t out_size,
    781                                   bool *present);
    782 
    783 
    784 /**
    785  * Extract fixed-size base32crockford encoded data from request header.
    786  *
    787  * Queues an error response to the connection if the parameter is missing or
    788  * invalid.
    789  *
    790  * @param connection the MHD connection
    791  * @param header_name the name of the HTTP header with the value
    792  * @param[out] out_data pointer to store the result
    793  * @param out_size expected size of @a out_data
    794  * @param[out] present set to true if argument was found
    795  * @return
    796  *   #GNUNET_YES if the the argument is present
    797  *   #GNUNET_NO if the argument is malformed
    798  *   #GNUNET_SYSERR on internal error (error response could not be sent)
    799  */
    800 enum GNUNET_GenericReturnValue
    801 TALER_MHD_parse_request_header_data (struct MHD_Connection *connection,
    802                                      const char *header_name,
    803                                      void *out_data,
    804                                      size_t out_size,
    805                                      bool *present);
    806 
    807 /**
    808  * Extract fixed-size base32crockford encoded data from request.
    809  *
    810  * @param connection the MHD connection
    811  * @param name the name of the parameter with the key
    812  * @param[out] val pointer to store the result, type must determine size
    813  * @param[in,out] required pass true to require presence of this argument; if 'false'
    814  *                         set to true if the argument was found
    815  * @return
    816  *   #GNUNET_YES if the the argument is present
    817  *   #GNUNET_NO if the argument is absent or malformed
    818  *   #GNUNET_SYSERR on internal error (error response could not be sent)
    819  */
    820 #define TALER_MHD_parse_request_arg_auto(connection,name,val,required) \
    821         do {                                                                 \
    822           bool p;                                                            \
    823           switch (TALER_MHD_parse_request_arg_data (connection, name,        \
    824                                                     val, sizeof (*val), &p)) \
    825           {                        \
    826           case GNUNET_SYSERR:      \
    827             GNUNET_break (0);      \
    828             return MHD_NO;         \
    829           case GNUNET_NO:          \
    830             GNUNET_break_op (0);   \
    831             return MHD_YES;        \
    832           case GNUNET_OK:          \
    833             if (required & (! p))  \
    834             {                      \
    835               GNUNET_break_op (0); \
    836               return TALER_MHD_reply_with_error (   \
    837                 connection,                         \
    838                 MHD_HTTP_BAD_REQUEST,               \
    839                 TALER_EC_GENERIC_PARAMETER_MISSING, \
    840                 name);                              \
    841             }                                       \
    842             required = p;                           \
    843             break;               \
    844           }                      \
    845         } while (0)
    846 
    847 
    848 /**
    849  * Extract required fixed-size base32crockford encoded data from request.
    850  *
    851  * @param connection the MHD connection
    852  * @param name the name of the parameter with the key
    853  * @param[out] val pointer to store the result, type must determine size
    854  * @return
    855  *   #GNUNET_YES if the the argument is present
    856  *   #GNUNET_NO if the argument is absent or malformed
    857  *   #GNUNET_SYSERR on internal error (error response could not be sent)
    858  */
    859 #define TALER_MHD_parse_request_arg_auto_t(connection,name,val) \
    860         do {                                                          \
    861           bool b = true;                                              \
    862           TALER_MHD_parse_request_arg_auto (connection,name,val,b);   \
    863         } while (0)
    864 
    865 /**
    866  * Extract fixed-size base32crockford encoded data from request.
    867  *
    868  * @param connection the MHD connection
    869  * @param name the name of the header with the key
    870  * @param[out] val pointer to store the result, type must determine size
    871  * @param[in,out] required pass true to require presence of this argument; if 'false'
    872  *                         set to true if the argument was found
    873  * @return
    874  *   #GNUNET_YES if the the argument is present
    875  *   #GNUNET_NO if the argument is absent or malformed
    876  *   #GNUNET_SYSERR on internal error (error response could not be sent)
    877  */
    878 #define TALER_MHD_parse_request_header_auto(connection,name,val,required)  \
    879         do {                                                               \
    880           bool p;                                                          \
    881           switch (TALER_MHD_parse_request_header_data (connection, name,   \
    882                                                        val, sizeof (*val), \
    883                                                        &p))                \
    884           {                       \
    885           case GNUNET_SYSERR:     \
    886             GNUNET_break (0);     \
    887             return MHD_NO;        \
    888           case GNUNET_NO:         \
    889             GNUNET_break_op (0);  \
    890             return MHD_YES;       \
    891           case GNUNET_OK:         \
    892             if (required & (! p)) \
    893             return TALER_MHD_reply_with_error (   \
    894               connection,                         \
    895               MHD_HTTP_BAD_REQUEST,               \
    896               TALER_EC_GENERIC_PARAMETER_MISSING, \
    897               name);                              \
    898             required = p;                         \
    899             break;               \
    900           }                      \
    901         } while (0)
    902 
    903 
    904 /**
    905  * Extract required fixed-size base32crockford encoded data from request.
    906  *
    907  * @param connection the MHD connection
    908  * @param name the name of the header with the key
    909  * @param[out] val pointer to store the result, type must determine size
    910  * @return
    911  *   #GNUNET_YES if the the argument is present
    912  *   #GNUNET_NO if the argument is absent or malformed
    913  *   #GNUNET_SYSERR on internal error (error response could not be sent)
    914  */
    915 #define TALER_MHD_parse_request_header_auto_t(connection,name,val) \
    916         do {                                                             \
    917           bool b = true;                                                 \
    918           TALER_MHD_parse_request_header_auto (connection,name,val,b);   \
    919         } while (0)
    920 
    921 
    922 /**
    923  * Check that the 'Content-Length' header is giving
    924  * a length below @a max_len. If not, return an
    925  * appropriate error response and return the
    926  * correct #MHD_YES/#MHD_NO value from this function.
    927  *
    928  * @param connection the MHD connection
    929  * @param max_len maximum allowed content length
    930  * @return
    931  *   #GNUNET_YES if the the argument is present
    932  *   #GNUNET_NO if the argument is absent or malformed
    933  *   #GNUNET_SYSERR on internal error (error response could not be sent)
    934  */
    935 enum GNUNET_GenericReturnValue
    936 TALER_MHD_check_content_length_ (struct MHD_Connection *connection,
    937                                  unsigned long long max_len);
    938 
    939 
    940 /**
    941  * Check that the 'Content-Length' header is giving
    942  * a length below @a max_len. If not, return an
    943  * appropriate error response and return the
    944  * correct #MHD_YES/#MHD_NO value from this function.
    945  *
    946  * @param connection the MHD connection
    947  * @param max_len maximum allowed content length
    948  */
    949 #define TALER_MHD_check_content_length(connection,max_len)         \
    950         do {                                                             \
    951           switch (TALER_MHD_check_content_length_ (connection, max_len)) \
    952           {                       \
    953           case GNUNET_SYSERR:     \
    954             GNUNET_break (0);     \
    955             return MHD_NO;        \
    956           case GNUNET_NO:         \
    957             GNUNET_break_op (0);  \
    958             return MHD_YES;       \
    959           case GNUNET_OK:         \
    960             break;                \
    961           }                       \
    962         } while (0)
    963 
    964 
    965 /**
    966  * Function called for logging by MHD.
    967  *
    968  * @param cls closure, NULL
    969  * @param fm format string (`printf()`-style)
    970  * @param ap arguments to @a fm
    971  */
    972 void
    973 TALER_MHD_handle_logs (void *cls,
    974                        const char *fm,
    975                        va_list ap);
    976 
    977 
    978 /**
    979  * Function called on each successfully bound listen
    980  * socket by #TALER_MHD_listen_bind().
    981  *
    982  * @param cls closure
    983  * @param fd bound listen socket (must be used and eventually
    984  *      closed by the callee). Never -1.
    985  */
    986 typedef void
    987 (*TALER_MHD_ListenSocketCallback)(void *cls,
    988                                   int fd);
    989 
    990 
    991 /**
    992  * Bind a listen socket to the UNIX domain path,
    993  * or the TCP port(s) and IP address(es) configured,
    994  * or return to @a cb the inherited sockets from systemd,
    995  * all depending on what was specified in @a cfg in
    996  * the section named @a section.
    997  *
    998  * @param cfg configuration to parse
    999  * @param section configuration section to use
   1000  * @param cb function to call with each bound socket
   1001  * @param cb_cls closure for @a cb
   1002  * @return #GNUNET_OK on success (all configured sockets were bound)
   1003  *         #GNUNET_NO if some configured binding failed but the config is OK,
   1004  *           note that some listen sockets may have been created
   1005  *         #GNUNET_SYSERR if the configuration is invalid
   1006  */
   1007 enum GNUNET_GenericReturnValue
   1008 TALER_MHD_listen_bind (const struct GNUNET_CONFIGURATION_Handle *cfg,
   1009                        const char *section,
   1010                        TALER_MHD_ListenSocketCallback cb,
   1011                        void *cb_cls);
   1012 
   1013 
   1014 /**
   1015  * Start to run an event loop for @a daemon.
   1016  *
   1017  * @param daemon the MHD service to run
   1018  */
   1019 void
   1020 TALER_MHD_daemon_start (struct MHD_Daemon *daemon);
   1021 
   1022 
   1023 /**
   1024  * Stop running the event loops of all MHD daemons.
   1025  */
   1026 void
   1027 TALER_MHD_daemons_halt (void);
   1028 
   1029 
   1030 /**
   1031  * Stop accepting new connections on all MHD daemons
   1032  * (and close the listen sockets).
   1033  */
   1034 void
   1035 TALER_MHD_daemons_quiesce (void);
   1036 
   1037 
   1038 /**
   1039  * Destroy all state associated with all MHD daemons.
   1040  */
   1041 void
   1042 TALER_MHD_daemons_destroy (void);
   1043 
   1044 /**
   1045  * Trigger all MHD daemons that were running. Needed when
   1046  * a connection was resumed.
   1047  */
   1048 void
   1049 TALER_MHD_daemon_trigger (void);
   1050 
   1051 
   1052 /**
   1053  * Prepared responses for legal documents
   1054  * (terms of service, privacy policy).
   1055  */
   1056 struct TALER_MHD_Legal;
   1057 
   1058 
   1059 /**
   1060  * Load set of legal documents as specified in @a cfg in section @a section
   1061  * where the Etag is given under the @a tagoption and the directory under
   1062  * the @a diroption.
   1063  *
   1064  * @param cfg configuration to use
   1065  * @param section section to load values from
   1066  * @param diroption name of the option with the
   1067  *        path to the legal documents
   1068  * @param tagoption name of the files to use
   1069  *        for the legal documents and the Etag
   1070  * @return NULL on error
   1071  */
   1072 struct TALER_MHD_Legal *
   1073 TALER_MHD_legal_load (const struct GNUNET_CONFIGURATION_Handle *cfg,
   1074                       const char *section,
   1075                       const char *diroption,
   1076                       const char *tagoption);
   1077 
   1078 
   1079 /**
   1080  * Free set of legal documents
   1081  *
   1082  * @param legal legal documents to free
   1083  */
   1084 void
   1085 TALER_MHD_legal_free (struct TALER_MHD_Legal *legal);
   1086 
   1087 
   1088 /**
   1089  * Generate a response with a legal document in
   1090  * the format and language of the user's choosing.
   1091  *
   1092  * @param conn HTTP connection to handle
   1093  * @param legal legal document to serve
   1094  * @return MHD result code
   1095  */
   1096 enum MHD_Result
   1097 TALER_MHD_reply_legal (struct MHD_Connection *conn,
   1098                        struct TALER_MHD_Legal *legal);
   1099 
   1100 
   1101 /**
   1102  * Send back a "204 No Content" response with headers
   1103  * for the CORS pre-flight request.
   1104  *
   1105  * @param connection the MHD connection
   1106  * @return MHD result code
   1107  */
   1108 enum MHD_Result
   1109 TALER_MHD_reply_cors_preflight (struct MHD_Connection *connection);
   1110 
   1111 
   1112 /**
   1113  * Load SPA files from @a dir, relative to the project's
   1114  * data directory.
   1115  *
   1116  *
   1117  * @param pd project data to use to determine the parent directory
   1118  * @param dir directory suffix to append to our data directory with the location of the files of the SPA
   1119  * @return handle to serve static files from @a dir
   1120  */
   1121 struct TALER_MHD_Spa *
   1122 TALER_MHD_spa_load (const struct GNUNET_OS_ProjectData *pd,
   1123                     const char *dir);
   1124 
   1125 /**
   1126  * Load SPA files from absolute path to directory @a dn.
   1127  *
   1128  *
   1129  * @param dn directory with the location of the files of the SPA,
   1130  *        should be an absolute path.
   1131  * @return handle to serve static files from @a dir
   1132  */
   1133 struct TALER_MHD_Spa *
   1134 TALER_MHD_spa_load_dir (const char *dn);
   1135 
   1136 
   1137 /**
   1138  * Release resources used by SPA handler.
   1139  *
   1140  * @param[in] spa data structure to release
   1141  */
   1142 void
   1143 TALER_MHD_spa_free (struct TALER_MHD_Spa *spa);
   1144 
   1145 
   1146 /**
   1147  * Handle HTTP request for files in a @a spa. Generates
   1148  * a 404 if no file at @a path does exists.
   1149  *
   1150  * @param spa the SPA to serve files from
   1151  * @param connection HTTP connection to return data on
   1152  * @param path request path to match against the @a spa
   1153  * @return MHD status code to give to MHD
   1154  */
   1155 enum MHD_Result
   1156 TALER_MHD_spa_handler (const struct TALER_MHD_Spa *spa,
   1157                        struct MHD_Connection *connection,
   1158                        const char *path);
   1159 
   1160 
   1161 /**
   1162  * Information about a document #TALER_MHD_typst() should output.
   1163  */
   1164 struct TALER_MHD_TypstDocument
   1165 {
   1166   /**
   1167    * Form name, used to determine the Typst template to use.
   1168    * NULL if @e data is a JSON string with a PDF to inline.
   1169    */
   1170   const char *form_name;
   1171 
   1172   /**
   1173    * Typst version of the form, if NULL we will use "0.0.0".
   1174    */
   1175   const char *form_version;
   1176 
   1177   /**
   1178    * Form data.
   1179    */
   1180   const json_t *data;
   1181 };
   1182 
   1183 
   1184 /**
   1185  * Context for generating PDF responses.
   1186  */
   1187 struct TALER_MHD_TypstContext;
   1188 
   1189 
   1190 /**
   1191  * Result from a #TALER_MHD_typst() operation.
   1192  */
   1193 struct TALER_MHD_TypstResponse
   1194 {
   1195 
   1196   /**
   1197    * Error status of the operation.
   1198    */
   1199   enum TALER_ErrorCode ec;
   1200 
   1201   /**
   1202    * Details depending on @e ec.
   1203    */
   1204   union
   1205   {
   1206     /**
   1207      * Hint if @e ec is not #TALER_EC_NONE.
   1208      */
   1209     const char *hint;
   1210 
   1211     /**
   1212      * Filename with the result if @e ec is #TALER_EC_NONE.
   1213      */
   1214     const char *filename;
   1215   } details;
   1216 
   1217 };
   1218 
   1219 /**
   1220  * Function called with the result of a #TALER_MHD_typst() operation.
   1221  *
   1222  * @param cls closure
   1223  * @param tr result of the operation
   1224  */
   1225 typedef void
   1226 (*TALER_MHD_TypstResultCallback) (void *cls,
   1227                                   const struct TALER_MHD_TypstResponse *tr);
   1228 
   1229 
   1230 /**
   1231  * Generate PDFs using Typst and combine them using pdftk.  The
   1232  * file will be returned to @a cb and after @a cb returns all data
   1233  * will be deleted from the local disk.
   1234  *
   1235  * @param pd project data to use
   1236  * @param cfg configuration to use (where to find Typst templates)
   1237  * @param remove_on_exit should the directory be removed when done?
   1238  * @param cfg_section_name name of the configuration section to use
   1239  * @param num_documents length of the @a docs array
   1240  * @param docs list of documents to combine into one large PDF
   1241  * @param cb function to call with the resulting file(name)
   1242  * @param cb_cls closure for @a cb
   1243  * @return NULL on error
   1244  */
   1245 struct TALER_MHD_TypstContext *
   1246 TALER_MHD_typst (
   1247   const struct GNUNET_OS_ProjectData *pd,
   1248   const struct GNUNET_CONFIGURATION_Handle *cfg,
   1249   bool remove_on_exit,
   1250   const char *cfg_section_name,
   1251   unsigned int num_documents,
   1252   const struct TALER_MHD_TypstDocument docs[static num_documents],
   1253   TALER_MHD_TypstResultCallback cb,
   1254   void *cb_cls);
   1255 
   1256 
   1257 /**
   1258  * Abort all typst response generation processes.
   1259  * To be used when the system is shutting down.
   1260  */
   1261 void
   1262 TALER_MHD_typst_cancel (struct TALER_MHD_TypstContext *tc);
   1263 
   1264 
   1265 /**
   1266  * Create HTTP response from the PDF file at @a filename
   1267  *
   1268  * @param filename file to return as PDF
   1269  * @return NULL on error
   1270  */
   1271 struct MHD_Response *
   1272 TALER_MHD_response_from_pdf_file (const char *filename);
   1273 
   1274 
   1275 #endif