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


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