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 (41604B)


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