commit 42c973c010b06d630cc2e94c906998c0db46f453
parent c2b2391bec10c9fc6090da32f49d797195af1fc2
Author: Iván Ávalos <avalos@disroot.org>
Date: Thu, 1 Oct 2026 14:33:03 +0200
remove mhd2 dependency
Diffstat:
9 files changed, 0 insertions(+), 3202 deletions(-)
diff --git a/meson.build b/meson.build
@@ -106,11 +106,6 @@ if not get_option('only-doc')
mhd_dep = cc.find_library('microhttpd', required: true)
endif
- mhd2_dep = dependency('libmicrohttpd2', required: false)
- if not mhd2_dep.found()
- mhd_dep2 = cc.find_library('microhttpd2', required: false)
- endif
-
json_dep = dependency('jansson', required: false)
if not json_dep.found()
json_dep = cc.find_library('jansson', required: true)
@@ -287,7 +282,6 @@ if not get_option('only-doc')
['libtalercurl', '1:0:1'],
['libtalerpq', '1:0:0'],
['libtalermhd', '8:0:1'],
- ['libtalermhd2', '0:0:0'],
['libtalertemplating', '1:1:1'],
['libtalerbank', '6:0:0'],
['libtalerkyclogic', '3:0:0'],
diff --git a/src/include/taler/meson.build b/src/include/taler/meson.build
@@ -28,10 +28,3 @@ foreach h : talerinclude_headers
install_headers(h, install_dir: get_option('includedir') / 'taler')
endforeach
-
-if mhd2_dep.found()
- install_headers(
- 'taler_mhd2_lib.h',
- install_dir: get_option('includedir') / 'taler',
- )
-endif
diff --git a/src/include/taler/taler_mhd2_lib.h b/src/include/taler/taler_mhd2_lib.h
@@ -1,1072 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014-2025 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file taler_mhd2_lib.h
- * @brief API for generating MHD replies
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- */
-#ifndef TALER_MHD2_LIB_H
-#define TALER_MHD2_LIB_H
-#include <gnunet/gnunet_util_lib.h>
-#include <gnunet/gnunet_json_lib.h>
-#include <jansson.h>
-#include <microhttpd2.h>
-#include <taler/taler_error_codes.h>
-#include <taler/taler_util.h>
-
-
-/**
- * Maximum POST request size.
- */
-#define TALER_MHD2_REQUEST_BUFFER_MAX (1024 * 1024 * 16)
-
-
-/**
- * Global options for response generation.
- */
-enum TALER_MHD2_GlobalOptions
-{
-
- /**
- * Use defaults.
- */
- TALER_MHD2_GO_NONE = 0,
-
- /**
- * Add "Connection: Close" header.
- */
- TALER_MHD2_GO_FORCE_CONNECTION_CLOSE = 1,
-
- /**
- * Disable use of compression, even if the client
- * supports it.
- */
- TALER_MHD2_GO_DISABLE_COMPRESSION = 2
-
-};
-
-
-/**
- * Find out if an MHD connection is using HTTPS (either
- * directly or via proxy).
- *
- * @param request MHD request
- * @returns #GNUNET_YES if the MHD connection is using https,
- * #GNUNET_NO if the MHD connection is using http,
- * #GNUNET_SYSERR if the connection type couldn't be determined
- */
-enum GNUNET_GenericReturnValue
-TALER_MHD2_is_https (struct MHD_Request *request);
-
-
-/**
- * Convert query argument to @a yna value.
- *
- * @param request request to take query argument from
- * @param arg argument to try for
- * @param default_val value to assign if the argument is not present
- * @param[out] yna value to set
- * @return true on success, false if the parameter was malformed
- */
-bool
-TALER_MHD2_arg_to_yna (struct MHD_Request *request,
- const char *arg,
- enum TALER_EXCHANGE_YesNoAll default_val,
- enum TALER_EXCHANGE_YesNoAll *yna);
-
-
-/**
- * Set global options for response generation within libtalermhd.
- *
- * @param go global options to use
- */
-void
-TALER_MHD2_setup (enum TALER_MHD2_GlobalOptions go);
-
-
-/**
- * Add headers we want to return in every response. Useful for testing, like
- * if we want to always close connections.
- *
- * @param response response to modify
- * @param allow_store set to true to NOT add a "Cache-Control"
- * directive that prevents caches and browsers from storing the data;
- * if false, we set "Cache-Control: no-store" (privacy by default);
- * set to true if the response contains no personal data
- */
-void
-TALER_MHD2_add_global_headers (struct MHD_Response *response,
- bool allow_store);
-
-
-/**
- * Try to compress a response body. Updates @a buf and @a buf_size.
- *
- * @param[in,out] buf pointer to body to compress
- * @param[in,out] buf_size pointer to initial size of @a buf
- * @return true if @a buf was compressed
- */
-bool
-TALER_MHD2_body_compress (void **buf,
- size_t *buf_size);
-
-
-/**
- * Is HTTP body deflate compression supported by the client?
- *
- * @param request the request to check
- * @return true if 'deflate' compression is allowed
- */
-bool
-TALER_MHD2_can_compress (struct MHD_Request *request);
-
-
-/**
- * Send JSON object as response.
- *
- * @param request the MHD request to handle, used to determine
- * whether compression is possible
- * @param json the json object
- * @param sc the http response code
- * @return MHD action
- */
-const struct MHD_Action *
-TALER_MHD2_reply_json (struct MHD_Request *request,
- const json_t *json,
- enum MHD_HTTP_StatusCode sc);
-
-
-/**
- * Send JSON object as response, and free the @a json
- * object.
- *
- * @param request the MHD request to handle
- * @param json the json object (freed!)
- * @param sc the http response code
- * @return MHD action
- */
-const struct MHD_Action *
-TALER_MHD2_reply_json_steal (struct MHD_Request *request,
- json_t *json,
- enum MHD_HTTP_StatusCode sc);
-
-
-/**
- * Make JSON response object.
- *
- * @param sc HTTP response code to use
- * @param json the json object
- * @return MHD response object
- */
-struct MHD_Response *
-TALER_MHD2_make_json (enum MHD_HTTP_StatusCode sc,
- const json_t *json);
-
-
-/**
- * Make JSON response object and free @a json.
- *
- * @param sc HTTP response code to use
- * @param json the json object, freed.
- * @return MHD response object
- */
-struct MHD_Response *
-TALER_MHD2_make_json_steal (enum MHD_HTTP_StatusCode sc,
- json_t *json);
-
-
-/**
- * Make response object
- *
- * @param sc HTTP status code to use
- * @param ... varargs
- * @return MHD action
- */
-#define TALER_MHD2_MAKE_JSON_PACK(sc,...) \
- TALER_MHD2_make_json_steal (sc, GNUNET_JSON_PACK (__VA_ARGS__))
-
-
-/**
- * Pack Taler error code @a ec and associated hint into a
- * JSON object.
- *
- * @param ec error code to pack
- * @return packer array entries (two!)
- */
-#define TALER_MHD2_PACK_EC(ec) \
- GNUNET_JSON_pack_uint64 ("code", ec), \
- GNUNET_JSON_pack_string ("hint", TALER_ErrorCode_get_hint (ec))
-
-/**
- * Create a response indicating an internal error.
- *
- * @param ec error code to return
- * @param detail additional optional detail about the error, can be NULL
- * @return a MHD response object
- */
-struct MHD_Response *
-TALER_MHD2_make_error (enum TALER_ErrorCode ec,
- const char *detail);
-
-
-/**
- * Function to call to handle the request by building a JSON
- * reply from varargs.
- *
- * @param request the MHD request to handle
- * @param sc HTTP response code to use
- * @param ... varargs of JSON pack specification
- * @return MHD action
- */
-#define TALER_MHD2_REPLY_JSON_PACK(request,sc,...) \
- TALER_MHD2_reply_json_steal (request, GNUNET_JSON_PACK (__VA_ARGS__), \
- sc)
-
-
-/**
- * Send a response indicating an error.
- *
- * @param request the MHD request to use
- * @param sc HTTP status code to use
- * @param ec error code uniquely identifying the error
- * @param detail additional optional detail about the error
- * @return MHD action
- */
-const struct MHD_Action *
-TALER_MHD2_reply_with_error (struct MHD_Request *request,
- enum MHD_HTTP_StatusCode sc,
- enum TALER_ErrorCode ec,
- const char *detail);
-
-
-/**
- * Send a response indicating an error. The HTTP status code is
- * to be derived from the @a ec.
- *
- * @param request the MHD request to use
- * @param ec error code uniquely identifying the error
- * @param detail additional optional detail about the error
- * @return MHD action
- */
-const struct MHD_Action *
-TALER_MHD2_reply_with_ec (struct MHD_Request *request,
- enum TALER_ErrorCode ec,
- const char *detail);
-
-
-/**
- * Produce HTTP "Date:" header.
- *
- * @param at time to write to @a date
- * @param[out] date where to write the header, with
- * at least 128 bytes available space.
- */
-void
-TALER_MHD2_get_date_string (struct GNUNET_TIME_Absolute at,
- char date[128]);
-
-
-/**
- * Send a response indicating that the request was too big.
- *
- * @param request the MHD request to use
- * @return MHD action
- */
-const struct MHD_Action *
-TALER_MHD2_reply_request_too_large (struct MHD_Request *request);
-
-
-/**
- * Function to call to handle the request by sending
- * back a redirect to the AGPL source code.
- *
- * @param request the MHD request to handle
- * @param url where to redirect for the sources
- * @return MHD action
- */
-const struct MHD_Action *
-TALER_MHD2_reply_agpl (struct MHD_Request *request,
- const char *url);
-
-
-/**
- * Function to call to handle the request by sending
- * back static data.
- *
- * @param request the MHD request to handle
- * @param sc status code to return
- * @param mime_type content-type to use
- * @param body response payload
- * @param body_size number of bytes in @a body
- * @return MHD action
- */
-const struct MHD_Action *
-TALER_MHD2_reply_static (struct MHD_Request *request,
- enum MHD_HTTP_StatusCode sc,
- const char *mime_type,
- const char *body,
- size_t body_size);
-
-
-/* The request-parsing surface below has not been ported to MHD2 yet:
- none of the functions it declares is implemented anywhere, so the
- block must stay disabled until src/mhd/mhd2_parsing.c exists. Note
- that "#if 0" is deliberate: a guard on an undefined macro name would
- silently flip meaning as soon as anything defines that name, handing
- the user a header that compiles and then fails to link. */
-#if 0
-
-/**
- * Process a POST request containing a JSON object. This
- * function realizes an MHD POST processor that will
- * (incrementally) process JSON data uploaded to the HTTP
- * server. It will store the required state in the
- * "request_cls", which must be cleaned up using
- * #TALER_MHD2_parse_post_cleanup_callback().
- *
- * @param request the MHD request
- * @param con_cls the closure (points to a `struct Buffer *`)
- * @param upload_data the POST data
- * @param upload_data_size number of bytes in @a upload_data
- * @param json the JSON object for a completed request
- * @return
- * #GNUNET_YES if json object was parsed or at least
- * may be parsed in the future (call again);
- * `*json` will be NULL if we need to be called again,
- * and non-NULL if we are done.
- * #GNUNET_NO is request incomplete or invalid
- * (error message was generated)
- * #GNUNET_SYSERR on internal error
- * (we could not even queue an error message,
- * close HTTP session with MHD_NO)
- */
-enum GNUNET_GenericReturnValue
-TALER_MHD2_parse_post_json (struct MHD_Request *request,
- void **con_cls,
- const char *upload_data,
- size_t *upload_data_size,
- json_t **json);
-
-
-/**
- * Function called whenever we are done with a request
- * to clean up our state.
- *
- * @param con_cls value as it was left by
- * #TALER_MHD2_parse_post_json(), to be cleaned up
- */
-void
-TALER_MHD2_parse_post_cleanup_callback (void *con_cls);
-
-
-/**
- * Parse JSON object into components based on the given field
- * specification. If parsing fails, we return an HTTP
- * status code of 400 (#MHD_HTTP_BAD_REQUEST).
- *
- * @param request the request to send an error response to
- * @param root the JSON node to start the navigation at.
- * @param spec field specification for the parser
- * @return
- * #GNUNET_YES if navigation was successful (caller is responsible
- * for freeing allocated variable-size data using
- * GNUNET_JSON_parse_free() when done)
- * #GNUNET_NO if json is malformed, error response was generated
- * #GNUNET_SYSERR on internal error
- */
-enum GNUNET_GenericReturnValue
-TALER_MHD2_parse_json_data (struct MHD_Request *request,
- const json_t *root,
- struct GNUNET_JSON_Specification *spec);
-
-
-/**
- * Parse JSON object that we (the server!) generated into components based on
- * the given field specification. The difference to
- * #TALER_MHD2_parse_json_data() is that this function will fail
- * with an HTTP failure of 500 (internal server error) in case
- * parsing fails, instead of blaming it on the client with a
- * 400 (#MHD_HTTP_BAD_REQUEST).
- *
- * @param request the request to send an error response to
- * @param root the JSON node to start the navigation at.
- * @param spec field specification for the parser
- * @return
- * #GNUNET_YES if navigation was successful (caller is responsible
- * for freeing allocated variable-size data using
- * GNUNET_JSON_parse_free() when done)
- * #GNUNET_NO if json is malformed, error response was generated
- * #GNUNET_SYSERR on internal error
- */
-enum GNUNET_GenericReturnValue
-TALER_MHD2_parse_internal_json_data (struct MHD_Request *request,
- const json_t *root,
- struct GNUNET_JSON_Specification *spec);
-
-
-/**
- * Parse JSON array into components based on the given field
- * specification. Generates error response on parse errors.
- *
- * @param request the request to send an error response to
- * @param root the JSON node to start the navigation at.
- * @param[in,out] spec field specification for the parser
- * @param ... -1-terminated list of array offsets of type 'int'
- * @return
- * #GNUNET_YES if navigation was successful (caller is responsible
- * for freeing allocated variable-size data using
- * GNUNET_JSON_parse_free() when done)
- * #GNUNET_NO if json is malformed, error response was generated
- * #GNUNET_SYSERR on internal error
- */
-enum GNUNET_GenericReturnValue
-TALER_MHD2_parse_json_array (struct MHD_Request *request,
- const json_t *root,
- struct GNUNET_JSON_Specification *spec,
- ...);
-
-
-/**
- * Extract optional "timeout_ms" argument from request.
- *
- * @param request the MHD request
- * @param[out] expiration set to #GNUNET_TIME_UNIT_ZERO_ABS if there was no timeout,
- * the current time plus the value given under "timeout_ms" otherwise
- * @return #GNUNET_OK on success, #GNUNET_NO if an
- * error was returned on @a request (caller should return #MHD_YES) and
- * #GNUNET_SYSERR if we failed to return an error (caller should return #MHD_NO)
- */
-enum GNUNET_GenericReturnValue
-TALER_MHD2_parse_request_arg_timeout (struct MHD_Request *request,
- struct GNUNET_TIME_Absolute *expiration);
-
-
-/**
- * Extract optional "timeout_ms" argument from request.
- * Macro that *returns* #MHD_YES/#MHD_NO if the "timeout_ms"
- * argument existed but failed to parse.
- *
- * @param request the MHD request
- * @param[out] expiration set to #GNUNET_TIME_UNIT_ZERO_ABS if there was no timeout,
- * the current time plus the value given under "timeout_ms" otherwise
- */
-#define TALER_MHD2_parse_request_timeout(request,expiration) \
- do { \
- switch (TALER_MHD2_parse_request_arg_timeout (request, \
- expiration)) \
- { \
- case GNUNET_SYSERR: \
- GNUNET_break (0); \
- return MHD_NO; \
- case GNUNET_NO: \
- GNUNET_break_op (0); \
- case GNUNET_OK: \
- break; \
- } \
- } while (0)
-
-
-/**
- * Extract optional timestamp argument from request.
- *
- * @param request the MHD request
- * @param fname name of the argument to parse
- * @param[out] ts set to #GNUNET_TIME_UNIT_ZERO_TS if there was no timestamp
- * @return #GNUNET_OK on success, #GNUNET_NO if an
- * error was returned on @a request (caller should return #MHD_YES) and
- * #GNUNET_SYSERR if we failed to return an error (caller should return #MHD_NO)
- */
-enum GNUNET_GenericReturnValue
-TALER_MHD2_parse_request_arg_timestamp (struct MHD_Request *request,
- const char *fname,
- struct GNUNET_TIME_Timestamp *ts);
-
-
-/**
- * Extract optional timestamp argument from request.
- * Macro that *returns* #MHD_YES/#MHD_NO if the timestamp
- * argument existed but failed to parse.
- *
- * @param request the MHD request
- * @param fname name of the argument
- * @param[out] ts set to #GNUNET_TIME_UNIT_ZERO_TS if there was no timestamp
- */
-#define TALER_MHD2_parse_request_timestamp(request,fname,ts) \
- do { \
- switch (TALER_MHD2_parse_request_arg_timestamp (request, \
- fname, \
- ts)) \
- { \
- case GNUNET_SYSERR: \
- GNUNET_break (0); \
- return MHD_NO; \
- case GNUNET_NO: \
- GNUNET_break_op (0); \
- case GNUNET_OK: \
- break; \
- } \
- } while (0)
-
-
-/**
- * Extract optional "yes/no/all" argument from request.
- * Macro that *returns* #MHD_YES/#MHD_NO if the
- * argument existed but failed to parse.
- *
- * @param request the MHD request
- * @param name name of the query parameter to parse
- * @param def default value to set if absent
- * @param[out] ret set to the yes/no/all value
- */
-#define TALER_MHD2_parse_request_yna(request,name,def,ret) \
- do { \
- if (! (TALER_arg_to_yna (request, \
- name, \
- def, \
- ret)) ) \
- { \
- GNUNET_break_op (0); \
- return TALER_MHD2_reply_with_error ( \
- request, \
- MHD_HTTP_BAD_REQUEST, \
- TALER_EC_GENERIC_PARAMETER_MALFORMED, \
- name); \
- } \
- } while (0)
-
-/**
- * Extract optional numeric limit argument from request.
- *
- * @param request the MHD request
- * @param name name of the query parameter
- * @param[out] off set to the offset, unchanged if the
- * option was not given
- * @return #GNUNET_OK on success,
- * #GNUNET_NO if an error was returned on @a request (caller should return #MHD_YES) and
- * #GNUNET_SYSERR if we failed to return an error (caller should return #MHD_NO)
- */
-enum GNUNET_GenericReturnValue
-TALER_MHD2_parse_request_arg_number (struct MHD_Request *request,
- const char *name,
- uint64_t *off);
-
-
-/**
- * Extract optional numeric argument from request.
- * Macro that *returns* #MHD_YES/#MHD_NO if the
- * requested argument existed but failed to parse.
- *
- * @param request the MHD request
- * @param name name of the argument to parse
- * @param[out] off set to the given numeric value,
- * unchanged if value was not specified
- */
-#define TALER_MHD2_parse_request_number(request,name,off) \
- do { \
- switch (TALER_MHD2_parse_request_arg_number (request, \
- name, \
- off)) \
- { \
- case GNUNET_SYSERR: \
- GNUNET_break (0); \
- return MHD_NO; \
- case GNUNET_NO: \
- GNUNET_break_op (0); \
- case GNUNET_OK: \
- break; \
- } \
- } while (0)
-
-
-/**
- * Extract optional signed numeric limit argument from request.
- *
- * @param request the MHD request
- * @param name name of the query parameter
- * @param[out] val set to the signed value, unchanged if the
- * option was not given
- * @return #GNUNET_OK on success,
- * #GNUNET_NO if an error was returned on @a request (caller should return #MHD_YES) and
- * #GNUNET_SYSERR if we failed to return an error (caller should return #MHD_NO)
- */
-enum GNUNET_GenericReturnValue
-TALER_MHD2_parse_request_arg_snumber (struct MHD_Request *request,
- const char *name,
- int64_t *val);
-
-
-/**
- * Extract optional numeric argument from request.
- * Macro that *returns* #MHD_YES/#MHD_NO if the
- * requested argument existed but failed to parse.
- *
- * @param request the MHD request
- * @param name name of the argument to parse
- * @param[out] val set to the given numeric value,
- * unchanged if value was not specified
- */
-#define TALER_MHD2_parse_request_snumber(request,name,val) \
- do { \
- switch (TALER_MHD2_parse_request_arg_snumber (request, \
- name, \
- val)) \
- { \
- case GNUNET_SYSERR: \
- GNUNET_break (0); \
- return MHD_NO; \
- case GNUNET_NO: \
- GNUNET_break_op (0); \
- case GNUNET_OK: \
- break; \
- } \
- } while (0)
-
-
-/**
- * Extract optional amount argument from request.
- *
- * @param request the MHD request
- * @param name name of the query parameter
- * @param[out] val set to the amount, unchanged if the
- * option was not given
- * @return #GNUNET_OK on success,
- * #GNUNET_NO if an error was returned on @a request (caller should return #MHD_YES) and
- * #GNUNET_SYSERR if we failed to return an error (caller should return #MHD_NO)
- */
-enum GNUNET_GenericReturnValue
-TALER_MHD2_parse_request_arg_amount (struct MHD_Request *request,
- const char *name,
- struct TALER_Amount *val);
-
-
-/**
- * Extract optional amount argument from request. Macro that *returns*
- * #MHD_YES/#MHD_NO if the requested argument existed but failed to parse.
- *
- * @param request the MHD request
- * @param name name of the argument to parse
- * @param[out] val set to the given amount,
- * unchanged if value was not specified
- */
-#define TALER_MHD2_parse_request_amount(request,name,val) \
- do { \
- switch (TALER_MHD2_parse_request_arg_amount (request, \
- name, \
- val)) \
- { \
- case GNUNET_SYSERR: \
- GNUNET_break (0); \
- return MHD_NO; \
- case GNUNET_NO: \
- GNUNET_break_op (0); \
- case GNUNET_OK: \
- break; \
- } \
- } while (0)
-
-
-/**
- * Extract fixed-size base32crockford encoded data from request argument.
- *
- * Queues an error response to the request if the parameter is missing or
- * invalid.
- *
- * @param request the MHD request
- * @param param_name the name of the parameter with the key
- * @param[out] out_data pointer to store the result
- * @param out_size expected size of @a out_data
- * @param[out] present set to true if argument was found
- * @return
- * #GNUNET_YES if the the argument is present
- * #GNUNET_NO if the argument is malformed
- * #GNUNET_SYSERR on internal error (error response could not be sent)
- */
-enum GNUNET_GenericReturnValue
-TALER_MHD2_parse_request_arg_data (struct MHD_Request *request,
- const char *param_name,
- void *out_data,
- size_t out_size,
- bool *present);
-
-
-/**
- * Extract fixed-size base32crockford encoded data from request header.
- *
- * Queues an error response to the request if the parameter is missing or
- * invalid.
- *
- * @param request the MHD request
- * @param header_name the name of the HTTP header with the value
- * @param[out] out_data pointer to store the result
- * @param out_size expected size of @a out_data
- * @param[out] present set to true if argument was found
- * @return
- * #GNUNET_YES if the the argument is present
- * #GNUNET_NO if the argument is malformed
- * #GNUNET_SYSERR on internal error (error response could not be sent)
- */
-enum GNUNET_GenericReturnValue
-TALER_MHD2_parse_request_header_data (struct MHD_Request *request,
- const char *header_name,
- void *out_data,
- size_t out_size,
- bool *present);
-
-/**
- * Extract fixed-size base32crockford encoded data from request.
- *
- * @param request the MHD request
- * @param name the name of the parameter with the key
- * @param[out] val pointer to store the result, type must determine size
- * @param[in,out] required pass true to require presence of this argument; if 'false'
- * set to true if the argument was found
- * @return
- * #GNUNET_YES if the the argument is present
- * #GNUNET_NO if the argument is absent or malformed
- * #GNUNET_SYSERR on internal error (error response could not be sent)
- */
-#define TALER_MHD2_parse_request_arg_auto(request,name,val,required) \
- do { \
- bool p; \
- switch (TALER_MHD2_parse_request_arg_data (request, name, \
- val, sizeof (*val), &p)) \
- { \
- case GNUNET_SYSERR: \
- GNUNET_break (0); \
- return MHD_NO; \
- case GNUNET_NO: \
- GNUNET_break_op (0); \
- return MHD_YES; \
- case GNUNET_OK: \
- if (required & (! p)) \
- { \
- GNUNET_break_op (0); \
- return TALER_MHD2_reply_with_error ( \
- request, \
- MHD_HTTP_BAD_REQUEST, \
- TALER_EC_GENERIC_PARAMETER_MISSING, \
- name); \
- } \
- required = p; \
- break; \
- } \
- } while (0)
-
-
-/**
- * Extract required fixed-size base32crockford encoded data from request.
- *
- * @param request the MHD request
- * @param name the name of the parameter with the key
- * @param[out] val pointer to store the result, type must determine size
- * @return
- * #GNUNET_YES if the the argument is present
- * #GNUNET_NO if the argument is absent or malformed
- * #GNUNET_SYSERR on internal error (error response could not be sent)
- */
-#define TALER_MHD2_parse_request_arg_auto_t(request,name,val) \
- do { \
- bool b = true; \
- TALER_MHD2_parse_request_arg_auto (request,name,val,b); \
- } while (0)
-
-/**
- * Extract fixed-size base32crockford encoded data from request.
- *
- * @param request the MHD request
- * @param name the name of the header with the key
- * @param[out] val pointer to store the result, type must determine size
- * @param[in,out] required pass true to require presence of this argument; if 'false'
- * set to true if the argument was found
- * @return
- * #GNUNET_YES if the the argument is present
- * #GNUNET_NO if the argument is absent or malformed
- * #GNUNET_SYSERR on internal error (error response could not be sent)
- */
-#define TALER_MHD2_parse_request_header_auto(request,name,val,required) \
- do { \
- bool p; \
- switch (TALER_MHD2_parse_request_header_data (request, name, \
- val, sizeof (*val), &p)) \
- { \
- case GNUNET_SYSERR: \
- GNUNET_break (0); \
- return MHD_NO; \
- case GNUNET_NO: \
- GNUNET_break_op (0); \
- return MHD_YES; \
- case GNUNET_OK: \
- if (required & (! p)) \
- return TALER_MHD2_reply_with_error ( \
- request, \
- MHD_HTTP_BAD_REQUEST, \
- TALER_EC_GENERIC_PARAMETER_MISSING, \
- name); \
- required = p; \
- break; \
- } \
- } while (0)
-
-
-/**
- * Extract required fixed-size base32crockford encoded data from request.
- *
- * @param request the MHD request
- * @param name the name of the header with the key
- * @param[out] val pointer to store the result, type must determine size
- * @return
- * #GNUNET_YES if the the argument is present
- * #GNUNET_NO if the argument is absent or malformed
- * #GNUNET_SYSERR on internal error (error response could not be sent)
- */
-#define TALER_MHD2_parse_request_header_auto_t(request,name,val) \
- do { \
- bool b = true; \
- TALER_MHD2_parse_request_header_auto (request,name,val,b); \
- } while (0)
-
-
-/**
- * Check that the 'Content-Length' header is giving
- * a length below @a max_len. If not, return an
- * appropriate error response and return the
- * correct #MHD_YES/#MHD_NO value from this function.
- *
- * @param request the MHD request
- * @param max_len maximum allowed content length
- * @return
- * #GNUNET_YES if the the argument is present
- * #GNUNET_NO if the argument is absent or malformed
- * #GNUNET_SYSERR on internal error (error response could not be sent)
- */
-enum GNUNET_GenericReturnValue
-TALER_MHD2_check_content_length_ (struct MHD_Request *request,
- unsigned long long max_len);
-
-
-/**
- * Check that the 'Content-Length' header is giving
- * a length below @a max_len. If not, return an
- * appropriate error response and return the
- * correct #MHD_YES/#MHD_NO value from this function.
- *
- * @param request the MHD request
- * @param max_len maximum allowed content length
- */
-#define TALER_MHD2_check_content_length(request,max_len) \
- do { \
- switch (TALER_MHD2_check_content_length_ (request, max_len)) \
- { \
- case GNUNET_SYSERR: \
- GNUNET_break (0); \
- return MHD_NO; \
- case GNUNET_NO: \
- GNUNET_break_op (0); \
- return MHD_YES; \
- case GNUNET_OK: \
- break; \
- } \
- } while (0)
-
-#endif
-
-
-/**
- * Function called for logging by MHD.
- *
- * @param cls closure, NULL
- * @param fm format string (`printf()`-style)
- * @param ap arguments to @a fm
- */
-void
-TALER_MHD_handle_logs (void *cls,
- const char *fm,
- va_list ap);
-
-
-/**
- * Function called on each successfully bound listen
- * socket by #TALER_MHD_listen_bind().
- *
- * @param cls closure
- * @param fd bound listen socket (must be used and eventually
- * closed by the callee). Never -1.
- */
-typedef void
-(*TALER_MHD_ListenSocketCallback)(void *cls,
- int fd);
-
-
-/**
- * Bind a listen socket to the UNIX domain path,
- * or the TCP port(s) and IP address(es) configured,
- * or return to @a cb the inherited sockets from systemd,
- * all depending on what was specified in @a cfg in
- * the section named @a section.
- *
- * @param cfg configuration to parse
- * @param section configuration section to use
- * @param cb function to call with each bound socket
- * @param cb_cls closure for @a cb
- * @return #GNUNET_OK on success (all configured sockets were bound)
- * #GNUNET_NO if some configured binding failed but the config is OK,
- * note that some listen sockets may have been created
- * #GNUNET_SYSERR if the configuration is invalid
- */
-enum GNUNET_GenericReturnValue
-TALER_MHD_listen_bind (const struct GNUNET_CONFIGURATION_Handle *cfg,
- const char *section,
- TALER_MHD_ListenSocketCallback cb,
- void *cb_cls);
-
-
-/**
- * Start to run an event loop for @a daemon.
- * Only one daemon can be running per process
- * using this API.
- *
- * @param daemon the MHD service to run
- */
-void
-TALER_MHD2_daemon_start (struct MHD_Daemon *daemon);
-
-
-/**
- * Stop running the event loops of all MHD daemons.
- */
-void
-TALER_MHD2_daemons_halt (void);
-
-
-/**
- * Stop accepting new connections on all MHD daemons
- * (and close the listen sockets).
- */
-void
-TALER_MHD2_daemons_quiesce (void);
-
-/**
- * Wake up all daemons.
- */
-void
-TALER_MHD2_daemons_trigger (void);
-
-/**
- * Destroy all state associated with all MHD daemons.
- */
-void
-TALER_MHD2_daemons_destroy (void);
-
-
-/**
- * Prepared responses for legal documents
- * (terms of service, privacy policy).
- */
-struct TALER_MHD2_Legal;
-
-
-/**
- * Load set of legal documents as specified in @a cfg in section @a section
- * where the Etag is given under the @a tagoption and the directory under
- * the @a diroption.
- *
- * @param cfg configuration to use
- * @param section section to load values from
- * @param diroption name of the option with the
- * path to the legal documents
- * @param tagoption name of the files to use
- * for the legal documents and the Etag
- * @return NULL on error
- */
-struct TALER_MHD2_Legal *
-TALER_MHD2_legal_load (const struct GNUNET_CONFIGURATION_Handle *cfg,
- const char *section,
- const char *diroption,
- const char *tagoption);
-
-
-/**
- * Free set of legal documents
- *
- * @param legal legal documents to free
- */
-void
-TALER_MHD2_legal_free (struct TALER_MHD2_Legal *legal);
-
-
-/**
- * Generate a response with a legal document in
- * the format and language of the user's choosing.
- *
- * @param conn HTTP request to handle
- * @param legal legal document to serve
- * @return MHD action
- */
-const struct MHD_Action *
-TALER_MHD2_reply_legal (struct MHD_Request *conn,
- struct TALER_MHD2_Legal *legal);
-
-
-/**
- * Send back a "204 No Content" response with headers
- * for the CORS pre-flight request.
- *
- * @param request the MHD request
- * @return MHD action
- */
-const struct MHD_Action *
-TALER_MHD2_reply_cors_preflight (struct MHD_Request *request);
-
-
-/**
- * Load SPA files from @a dir
- *
- * @param pd project data to use to determine the parent directory
- * @param dir directory suffix to append to our data directory with the location of the files of the SPA
- * @return handle to serve static files from @a dir
- */
-struct TALER_MHD2_Spa *
-TALER_MHD2_spa_load (const struct GNUNET_OS_ProjectData *pd,
- const char *dir);
-
-
-/**
- * Release resources used by SPA handler.
- *
- * @param[in] spa data structure to release
- */
-void
-TALER_MHD2_spa_free (struct TALER_MHD2_Spa *spa);
-
-
-/**
- * Handle HTTP request for files in a @a spa. Generates
- * a 404 if no file at @a path does exists.
- *
- * @param spa the SPA to serve files from
- * @param request HTTP request to return data on
- * @param path request path to match against the @a spa
- * @return MHD action
- */
-const struct MHD_Action *
-TALER_MHD2_spa_handler (const struct TALER_MHD2_Spa *spa,
- struct MHD_Request *request,
- const char *path);
-
-
-#endif
diff --git a/src/mhd/meson.build b/src/mhd/meson.build
@@ -83,43 +83,3 @@ foreach t : talermhd_tests
)
endforeach
-if mhd2_dep.found()
-
- libtalermhd2_src = [
- 'mhd2.c',
- 'mhd_config.c',
- 'mhd2_legal.c',
- 'mhd2_responses.c',
- 'mhd2_run.c',
- 'mhd2_spa.c',
- ]
-
- libtalermhd2 = library(
- 'talermhd2',
- libtalermhd2_src,
- soversion: solibversions['libtalermhd2']['soversion'],
- version: solibversions['libtalermhd2']['soversion'],
- install_rpath: rpath_option,
- dependencies: [
- libtalerutil_dep,
- libtalerjson_dep,
- gnunetutil_dep,
- gnunetjson_dep,
- gnunetmhd_dep,
- json_dep,
- mhd2_dep,
- zlib_dep,
- ],
- include_directories: [incdir, configuration_inc],
- install: true,
- install_dir: get_option('libdir'),
- )
-
- libtalermhd2_dep = declare_dependency(link_with: libtalermhd2)
- pkg.generate(
- libtalermhd2,
- url: 'https://taler.net',
- description: 'GNU Taler microhttpd2 wrapper library',
- )
-
-endif
diff --git a/src/mhd/mhd2.c b/src/mhd/mhd2.c
@@ -1,109 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014-2025 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file mhd2.c
- * @brief MHD utility functions (used by the merchant backend)
- * @author Christian Grothoff
- */
-#include "taler/taler_util.h"
-#include "taler/taler_mhd2_lib.h"
-
-
-enum GNUNET_GenericReturnValue
-TALER_MHD2_is_https (struct MHD_Request *request)
-{
- struct MHD_StringNullable forwarded_proto;
- union MHD_RequestInfoFixedData ci;
- union MHD_DaemonInfoFixedData di;
-
- if ( (MHD_NO !=
- MHD_request_get_value (request,
- MHD_VK_HEADER,
- "X-Forwarded-Proto",
- &forwarded_proto)) &&
- (NULL != forwarded_proto.cstr) )
- {
- if (0 == strcasecmp (forwarded_proto.cstr,
- "https"))
- return GNUNET_YES;
- if (0 == strcasecmp (forwarded_proto.cstr,
- "http"))
- return GNUNET_NO;
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- /* likely not reverse proxy, figure out if we are
- http by asking MHD */
- if (MHD_SC_OK !=
- MHD_request_get_info_fixed (request,
- MHD_REQUEST_INFO_FIXED_DAEMON,
- &ci))
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- if (MHD_SC_OK !=
- MHD_daemon_get_info_fixed (ci.v_daemon,
- MHD_DAEMON_INFO_FIXED_TLS_BACKEND,
- &di))
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- if (MHD_TLS_BACKEND_NONE != di.v_tls_backend)
- return GNUNET_YES;
- return GNUNET_NO;
-}
-
-
-bool
-TALER_MHD2_arg_to_yna (struct MHD_Request *request,
- const char *arg,
- enum TALER_EXCHANGE_YesNoAll default_val,
- enum TALER_EXCHANGE_YesNoAll *yna)
-{
- struct MHD_StringNullable nstr;
-
- if ( (MHD_NO ==
- MHD_request_get_value (request,
- MHD_VK_URI_QUERY_PARAM,
- arg,
- &nstr)) ||
- (NULL == nstr.cstr) )
- {
- *yna = default_val;
- return true;
- }
- if (0 == strcasecmp (nstr.cstr,
- "yes"))
- {
- *yna = TALER_EXCHANGE_YNA_YES;
- return true;
- }
- if (0 == strcasecmp (nstr.cstr,
- "no"))
- {
- *yna = TALER_EXCHANGE_YNA_NO;
- return true;
- }
- if (0 == strcasecmp (nstr.cstr,
- "all"))
- {
- *yna = TALER_EXCHANGE_YNA_ALL;
- return true;
- }
- return false;
-}
diff --git a/src/mhd/mhd2_legal.c b/src/mhd/mhd2_legal.c
@@ -1,702 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2019--2025 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file mhd2_legal.c
- * @brief API for returning legal documents based on client language
- * and content type preferences
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <gnunet/gnunet_json_lib.h>
-#include <jansson.h>
-#include <microhttpd2.h>
-#include "taler/taler_util.h"
-#include "taler/taler_mhd2_lib.h"
-
-/**
- * How long should browsers/proxies cache the "legal" replies?
- */
-#define MAX_TERMS_CACHING GNUNET_TIME_UNIT_DAYS
-
-/**
- * HTTP header with the version of the terms of service.
- */
-#define TALER_TERMS_VERSION "Taler-Terms-Version"
-
-/**
- * Entry in the terms-of-service array.
- */
-struct Terms
-{
- /**
- * Kept in a DLL.
- */
- struct Terms *prev;
-
- /**
- * Kept in a DLL.
- */
- struct Terms *next;
-
- /**
- * Mime type of the terms.
- */
- const char *mime_type;
-
- /**
- * The terms (NOT 0-terminated!), mmap()'ed. Do not free,
- * use munmap() instead.
- */
- void *terms;
-
- /**
- * The desired language.
- */
- char *language;
-
- /**
- * deflated @e terms, to return if client supports deflate compression.
- * malloc()'ed. NULL if @e terms does not compress.
- */
- void *compressed_terms;
-
- /**
- * Etag we use for this response.
- */
- char *terms_etag;
-
- /**
- * Number of bytes in @e terms.
- */
- size_t terms_size;
-
- /**
- * Number of bytes in @e compressed_terms.
- */
- size_t compressed_terms_size;
-
- /**
- * Sorting key by format preference in case
- * everything else is equal. Higher is preferred.
- */
- unsigned int priority;
-
-};
-
-
-/**
- * Prepared responses for legal documents
- * (terms of service, privacy policy).
- */
-struct TALER_MHD2_Legal
-{
- /**
- * DLL of terms of service.
- */
- struct Terms *terms_head;
-
- /**
- * DLL of terms of service.
- */
- struct Terms *terms_tail;
-
- /**
- * Etag to use for the terms of service (= version).
- */
- char *terms_version;
-};
-
-
-const struct MHD_Action *
-TALER_MHD2_reply_legal (struct MHD_Request *request,
- struct TALER_MHD2_Legal *legal)
-{
- /* Default terms of service if none are configured */
- static struct Terms none = {
- .mime_type = "text/plain",
- .terms = (void *) "not configured",
- .language = (void *) "en",
- .terms_size = strlen ("not configured")
- };
- struct MHD_Response *resp;
- struct Terms *t;
- struct GNUNET_TIME_Absolute a;
- struct GNUNET_TIME_Timestamp m;
- char dat[128];
- char *langs;
-
- t = NULL;
- langs = NULL;
- a = GNUNET_TIME_relative_to_absolute (MAX_TERMS_CACHING);
- m = GNUNET_TIME_absolute_to_timestamp (a);
- /* Round up to next full day to ensure the expiration
- time does not become a fingerprint! */
- a = GNUNET_TIME_absolute_round_down (a,
- MAX_TERMS_CACHING);
- a = GNUNET_TIME_absolute_add (a,
- MAX_TERMS_CACHING);
- TALER_MHD2_get_date_string (m.abs_time,
- dat);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Setting '%s' header to '%s'\n",
- MHD_HTTP_HEADER_EXPIRES,
- dat);
- if (NULL == legal)
- {
- t = &none;
- goto return_t;
- }
-
- if (NULL != legal)
- {
- struct MHD_StringNullable mimen;
- struct MHD_StringNullable langn;
- const char *mime;
- const char *lang;
- double best_mime_q = 0.0;
- double best_lang_q = 0.0;
-
- if ( (MHD_NO ==
- MHD_request_get_value (request,
- MHD_VK_HEADER,
- MHD_HTTP_HEADER_ACCEPT,
- &mimen)) ||
- (NULL == mimen.cstr) )
- mime = "text/plain";
- else
- mime = mimen.cstr;
- if ( (MHD_NO ==
- MHD_request_get_value (request,
- MHD_VK_HEADER,
- MHD_HTTP_HEADER_ACCEPT_LANGUAGE,
- &langn)) ||
- (NULL == langn.cstr) )
- lang = "en";
- else
- lang = langn.cstr;
- /* Find best match: must match mime type (if possible), and if
- mime type matches, ideally also language */
- for (struct Terms *p = legal->terms_head;
- NULL != p;
- p = p->next)
- {
- double q;
-
- q = TALER_pattern_matches (mime,
- p->mime_type);
- if (q > best_mime_q)
- best_mime_q = q;
- }
- for (struct Terms *p = legal->terms_head;
- NULL != p;
- p = p->next)
- {
- double q;
-
- q = TALER_pattern_matches (mime,
- p->mime_type);
- if (q < best_mime_q)
- continue;
- if (NULL == langs)
- {
- langs = GNUNET_strdup (p->language);
- }
- else if (NULL == strstr (langs,
- p->language))
- {
- char *tmp = langs;
-
- GNUNET_asprintf (&langs,
- "%s,%s",
- tmp,
- p->language);
- GNUNET_free (tmp);
- }
- q = TALER_pattern_matches (lang,
- p->language);
- if (NULL != t)
- {
- if (q < best_lang_q)
- continue;
- /* Client expressed no preference between these two formats,
- so fall back to our own ranking instead of letting the
- last entry in the list win. */
- if ( (q <= best_lang_q) &&
- (p->priority <= t->priority) )
- continue;
- }
- best_lang_q = q;
- t = p;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Best match for %s/%s: %s / %s\n",
- lang,
- mime,
- (NULL != t) ? t->mime_type : "<none>",
- (NULL != t) ? t->language : "<none>");
- }
-
- if (NULL != t)
- {
- struct MHD_StringNullable etag;
-
- if ( (MHD_NO !=
- MHD_request_get_value (request,
- MHD_VK_HEADER,
- MHD_HTTP_HEADER_IF_NONE_MATCH,
- &etag)) &&
- (NULL != etag.cstr) &&
- (NULL != t->terms_etag) &&
- (0 == strcasecmp (etag.cstr,
- t->terms_etag)) )
- {
- resp = MHD_response_from_empty (MHD_HTTP_STATUS_NOT_MODIFIED);
- GNUNET_break (MHD_SC_OK ==
- MHD_RESPONSE_SET_OPTIONS (
- resp,
- MHD_R_OPTION_HEAD_ONLY_RESPONSE (true)));
- TALER_MHD2_add_global_headers (resp,
- true);
- GNUNET_break (MHD_SC_OK ==
- MHD_response_add_header (resp,
- MHD_HTTP_HEADER_EXPIRES,
- dat));
- GNUNET_break (MHD_SC_OK ==
- MHD_response_add_header (resp,
- MHD_HTTP_HEADER_ETAG,
- t->terms_etag));
- if (NULL != legal)
- GNUNET_break (MHD_SC_OK ==
- MHD_response_add_header (resp,
- TALER_TERMS_VERSION,
- legal->terms_version));
- return MHD_action_from_response (request,
- resp);
- }
- }
-
- if (NULL == t)
- t = &none; /* 501 if not configured */
-
-return_t:
- /* try to compress the response */
- resp = NULL;
- if ( (MHD_YES ==
- TALER_MHD2_can_compress (request)) &&
- (NULL != t->compressed_terms) )
- {
- resp = MHD_response_from_buffer_static (t == &none
- ? MHD_HTTP_STATUS_NOT_IMPLEMENTED
- : MHD_HTTP_STATUS_OK,
- t->compressed_terms_size,
- t->compressed_terms);
- if (MHD_SC_OK !=
- MHD_response_add_header (resp,
- MHD_HTTP_HEADER_CONTENT_ENCODING,
- "deflate"))
- {
- GNUNET_break (0);
- MHD_response_destroy (resp);
- resp = NULL;
- }
- }
- if (NULL == resp)
- {
- /* could not generate compressed response, return uncompressed */
- resp = MHD_response_from_buffer_static (t == &none
- ? MHD_HTTP_STATUS_NOT_IMPLEMENTED
- : MHD_HTTP_STATUS_OK,
- t->terms_size,
- (void *) t->terms);
- }
- TALER_MHD2_add_global_headers (resp,
- true);
- GNUNET_break (MHD_SC_OK ==
- MHD_response_add_header (resp,
- MHD_HTTP_HEADER_EXPIRES,
- dat));
- if (NULL != langs)
- {
- GNUNET_break (MHD_SC_OK ==
- MHD_response_add_header (resp,
- "Avail-Languages",
- langs));
- GNUNET_free (langs);
- }
- /* Set cache control headers: our response varies depending on these headers */
- GNUNET_break (MHD_SC_OK ==
- MHD_response_add_header (resp,
- MHD_HTTP_HEADER_VARY,
- MHD_HTTP_HEADER_ACCEPT_LANGUAGE ","
- MHD_HTTP_HEADER_ACCEPT ","
- MHD_HTTP_HEADER_ACCEPT_ENCODING));
- /* Information is always public, revalidate after 10 days */
- GNUNET_break (MHD_SC_OK ==
- MHD_response_add_header (resp,
- MHD_HTTP_HEADER_CACHE_CONTROL,
- "public,max-age=864000"));
- if (NULL != t->terms_etag)
- GNUNET_break (MHD_SC_OK ==
- MHD_response_add_header (resp,
- MHD_HTTP_HEADER_ETAG,
- t->terms_etag));
- if (NULL != legal)
- GNUNET_break (MHD_SC_OK ==
- MHD_response_add_header (resp,
- TALER_TERMS_VERSION,
- legal->terms_version));
- GNUNET_break (MHD_SC_OK ==
- MHD_response_add_header (resp,
- MHD_HTTP_HEADER_CONTENT_TYPE,
- t->mime_type));
- GNUNET_break (MHD_SC_OK ==
- MHD_response_add_header (resp,
- MHD_HTTP_HEADER_CONTENT_LANGUAGE,
- t->language));
- return MHD_action_from_response (request,
- resp);
-}
-
-
-/**
- * Load all the terms of service from @a path under language @a lang
- * from file @a name
- *
- * @param[in,out] legal where to write the result
- * @param path where the terms are found
- * @param lang which language directory to crawl
- * @param name specific file to access
- */
-static void
-load_terms (struct TALER_MHD2_Legal *legal,
- const char *path,
- const char *lang,
- const char *name)
-{
- static struct MimeMap
- {
- const char *ext;
- const char *mime;
- unsigned int priority;
- } mm[] = {
- { .ext = ".txt", .mime = "text/plain", .priority = 150 },
- { .ext = ".html", .mime = "text/html", .priority = 100 },
- { .ext = ".htm", .mime = "text/html", .priority = 99 },
- { .ext = ".md", .mime = "text/markdown", .priority = 50 },
- { .ext = ".pdf", .mime = "application/pdf", .priority = 25 },
- { .ext = ".jpg", .mime = "image/jpeg" },
- { .ext = ".jpeg", .mime = "image/jpeg" },
- { .ext = ".png", .mime = "image/png" },
- { .ext = ".gif", .mime = "image/gif" },
- { .ext = ".epub", .mime = "application/epub+zip", .priority = 10 },
- { .ext = ".xml", .mime = "text/xml", .priority = 10 },
- { .ext = NULL, .mime = NULL }
- };
- const char *ext = strrchr (name, '.');
- const char *mime;
- unsigned int priority;
-
- if (NULL == ext)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Unsupported file `%s' in directory `%s/%s': lacks extension\n",
- name,
- path,
- lang);
- return;
- }
- if ( (NULL == legal->terms_version) ||
- (0 != strncmp (legal->terms_version,
- name,
- ext - name)) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Filename `%s' does not match Etag `%s' in directory `%s/%s'. Ignoring it.\n",
- name,
- legal->terms_version,
- path,
- lang);
- return;
- }
- mime = NULL;
- for (unsigned int i = 0; NULL != mm[i].ext; i++)
- if (0 == strcasecmp (mm[i].ext,
- ext))
- {
- mime = mm[i].mime;
- priority = mm[i].priority;
- break;
- }
- if (NULL == mime)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Unsupported file extension `%s' of file `%s' in directory `%s/%s'\n",
- ext,
- name,
- path,
- lang);
- return;
- }
- /* try to read the file with the terms of service */
- {
- struct stat st;
- char *fn;
- int fd;
-
- GNUNET_asprintf (&fn,
- "%s/%s/%s",
- path,
- lang,
- name);
- fd = open (fn, O_RDONLY);
- if (-1 == fd)
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
- "open",
- fn);
- GNUNET_free (fn);
- return;
- }
- if (0 != fstat (fd, &st))
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
- "fstat",
- fn);
- GNUNET_break (0 == close (fd));
- GNUNET_free (fn);
- return;
- }
- if (SIZE_MAX < ((unsigned long long) st.st_size))
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
- "fstat-size",
- fn);
- GNUNET_break (0 == close (fd));
- GNUNET_free (fn);
- return;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Loading legal information from file `%s'\n",
- fn);
- {
- void *buf;
- size_t bsize;
-
- bsize = (size_t) st.st_size;
- buf = mmap (NULL,
- bsize,
- PROT_READ,
- MAP_SHARED,
- fd,
- 0);
- if (MAP_FAILED == buf)
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
- "mmap",
- fn);
- GNUNET_break (0 == close (fd));
- GNUNET_free (fn);
- return;
- }
- GNUNET_break (0 == close (fd));
- GNUNET_free (fn);
-
- /* insert into global list of terms of service */
- {
- struct Terms *t;
- struct GNUNET_HashCode hc;
-
- GNUNET_CRYPTO_hash (buf,
- bsize,
- &hc);
- t = GNUNET_new (struct Terms);
- t->mime_type = mime;
- t->terms = buf;
- t->language = GNUNET_strdup (lang);
- t->terms_size = bsize;
- t->priority = priority;
- t->terms_etag
- = GNUNET_STRINGS_data_to_string_alloc (&hc,
- sizeof (hc) / 2);
- buf = GNUNET_memdup (t->terms,
- t->terms_size);
- if (TALER_MHD2_body_compress (&buf,
- &bsize))
- {
- t->compressed_terms = buf;
- t->compressed_terms_size = bsize;
- }
- else
- {
- GNUNET_free (buf);
- }
- {
- struct Terms *prev = NULL;
-
- for (struct Terms *pos = legal->terms_head;
- NULL != pos;
- pos = pos->next)
- {
- if (pos->priority < priority)
- break;
- prev = pos;
- }
- GNUNET_CONTAINER_DLL_insert_after (legal->terms_head,
- legal->terms_tail,
- prev,
- t);
- }
- }
- }
- }
-}
-
-
-/**
- * Load all the terms of service from @a path under language @a lang.
- *
- * @param[in,out] legal where to write the result
- * @param path where the terms are found
- * @param lang which language directory to crawl
- */
-static void
-load_language (struct TALER_MHD2_Legal *legal,
- const char *path,
- const char *lang)
-{
- char *dname;
- DIR *d;
-
- GNUNET_asprintf (&dname,
- "%s/%s",
- path,
- lang);
- d = opendir (dname);
- if (NULL == d)
- {
- GNUNET_free (dname);
- return;
- }
- for (struct dirent *de = readdir (d);
- NULL != de;
- de = readdir (d))
- {
- const char *fn = de->d_name;
-
- if (fn[0] == '.')
- continue;
- load_terms (legal,
- path,
- lang,
- fn);
- }
- GNUNET_break (0 == closedir (d));
- GNUNET_free (dname);
-}
-
-
-struct TALER_MHD2_Legal *
-TALER_MHD2_legal_load (const struct GNUNET_CONFIGURATION_Handle *cfg,
- const char *section,
- const char *diroption,
- const char *tagoption)
-{
- struct TALER_MHD2_Legal *legal;
- char *path;
- DIR *d;
-
- legal = GNUNET_new (struct TALER_MHD2_Legal);
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- section,
- tagoption,
- &legal->terms_version))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
- section,
- tagoption);
- GNUNET_free (legal);
- return NULL;
- }
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_filename (cfg,
- section,
- diroption,
- &path))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
- section,
- diroption);
- GNUNET_free (legal->terms_version);
- GNUNET_free (legal);
- return NULL;
- }
- d = opendir (path);
- if (NULL == d)
- {
- GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
- section,
- diroption,
- "Could not open directory");
- GNUNET_free (legal->terms_version);
- GNUNET_free (legal);
- GNUNET_free (path);
- return NULL;
- }
- for (struct dirent *de = readdir (d);
- NULL != de;
- de = readdir (d))
- {
- const char *lang = de->d_name;
-
- if (lang[0] == '.')
- continue;
- if (0 == strcmp (lang,
- "locale"))
- continue;
- load_language (legal,
- path,
- lang);
- }
- GNUNET_break (0 == closedir (d));
- GNUNET_free (path);
- return legal;
-}
-
-
-void
-TALER_MHD2_legal_free (struct TALER_MHD2_Legal *legal)
-{
- struct Terms *t;
- if (NULL == legal)
- return;
- while (NULL != (t = legal->terms_head))
- {
- GNUNET_free (t->language);
- GNUNET_free (t->compressed_terms);
- if (0 != munmap (t->terms, t->terms_size))
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
- "munmap");
- GNUNET_CONTAINER_DLL_remove (legal->terms_head,
- legal->terms_tail,
- t);
- GNUNET_free (t->terms_etag);
- GNUNET_free (t);
- }
- GNUNET_free (legal->terms_version);
- GNUNET_free (legal);
-}
diff --git a/src/mhd/mhd2_responses.c b/src/mhd/mhd2_responses.c
@@ -1,462 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014-2025 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file mhd2_responses.c
- * @brief API for generating HTTP replies
- * @author Florian Dold
- * @author Benedikt Mueller
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <zlib.h>
-#include "taler/taler_util.h"
-#include "taler/taler_mhd2_lib.h"
-
-
-/**
- * Global options for response generation.
- */
-static enum TALER_MHD2_GlobalOptions TM_go;
-
-
-void
-TALER_MHD2_setup (enum TALER_MHD2_GlobalOptions go)
-{
- TM_go = go;
-}
-
-
-void
-TALER_MHD2_add_global_headers (struct MHD_Response *response,
- bool allow_store)
-{
- if (0 != (TM_go & TALER_MHD2_GO_FORCE_CONNECTION_CLOSE))
- GNUNET_break (MHD_SC_OK ==
- MHD_response_add_header (response,
- MHD_HTTP_HEADER_CONNECTION,
- "close"));
- /* The wallet, operating from a background page, needs CORS to
- be disabled otherwise browsers block access. */
- GNUNET_break (MHD_SC_OK ==
- MHD_response_add_header (response,
- MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
- "*"));
- GNUNET_break (MHD_SC_OK ==
- MHD_response_add_header (response,
- /* Not available as MHD constant yet */
- "Access-Control-Expose-Headers",
- "*"));
- if (! allow_store)
- GNUNET_break (MHD_SC_OK ==
- MHD_response_add_header (response,
- MHD_HTTP_HEADER_CACHE_CONTROL,
- "no-store"));
-}
-
-
-bool
-TALER_MHD2_can_compress (struct MHD_Request *request)
-{
- struct MHD_StringNullable aeb;
- const char *ae;
- const char *de;
-
- if (0 != (TM_go & TALER_MHD2_GO_DISABLE_COMPRESSION))
- return MHD_NO;
- if ( (MHD_NO ==
- MHD_request_get_value (request,
- MHD_VK_HEADER,
- MHD_HTTP_HEADER_ACCEPT_ENCODING,
- &aeb)) ||
- (NULL == aeb.cstr) )
- return false;
- ae = aeb.cstr;
- if (0 == strcmp (ae,
- "*"))
- return true;
- de = strstr (ae,
- "deflate");
- if (NULL == de)
- return false;
- if ( ( (de == ae) ||
- (de[-1] == ',') ||
- (de[-1] == ' ') ) &&
- ( (de[strlen ("deflate")] == '\0') ||
- (de[strlen ("deflate")] == ',') ||
- (de[strlen ("deflate")] == ';') ) )
- return true;
- return false;
-}
-
-
-bool
-TALER_MHD2_body_compress (void **buf,
- size_t *buf_size)
-{
- Bytef *cbuf;
- uLongf cbuf_size;
- int ret;
-
- cbuf_size = compressBound (*buf_size);
- cbuf = malloc (cbuf_size);
- if (NULL == cbuf)
- return false;
- ret = compress (cbuf,
- &cbuf_size,
- (const Bytef *) *buf,
- *buf_size);
- if ( (Z_OK != ret) ||
- (cbuf_size >= *buf_size) )
- {
- /* compression failed */
- free (cbuf);
- return false;
- }
- free (*buf);
- *buf = (void *) cbuf;
- *buf_size = (size_t) cbuf_size;
- return true;
-}
-
-
-struct MHD_Response *
-TALER_MHD2_make_json (enum MHD_HTTP_StatusCode sc,
- const json_t *json)
-{
- struct MHD_Response *response;
- char *json_str;
-
- json_str = json_dumps (json,
- JSON_INDENT (2));
- if (NULL == json_str)
- {
- GNUNET_break (0);
- return NULL;
- }
- response = MHD_response_from_buffer (sc,
- strlen (json_str),
- json_str,
- &free,
- json_str);
- if (NULL == response)
- {
- free (json_str);
- GNUNET_break (0);
- return NULL;
- }
- TALER_MHD2_add_global_headers (response,
- false);
- GNUNET_break (MHD_SC_OK ==
- MHD_response_add_header (response,
- MHD_HTTP_HEADER_CONTENT_TYPE,
- "application/json"));
- return response;
-}
-
-
-struct MHD_Response *
-TALER_MHD2_make_json_steal (enum MHD_HTTP_StatusCode sc,
- json_t *json)
-{
- struct MHD_Response *res;
-
- res = TALER_MHD2_make_json (sc,
- json);
- json_decref (json);
- return res;
-}
-
-
-const struct MHD_Action *
-TALER_MHD2_reply_json (struct MHD_Request *request,
- const json_t *json,
- enum MHD_HTTP_StatusCode sc)
-{
- struct MHD_Response *response;
- void *json_str;
- size_t json_len;
- bool is_compressed;
-
- json_str = json_dumps (json,
- JSON_INDENT (2));
- if (NULL == json_str)
- {
- /**
- * This log helps to figure out which
- * function called this one and assert-failed.
- */
- TALER_LOG_ERROR ("Aborting json-packing for HTTP code: %u\n",
- sc);
-
- GNUNET_assert (0);
- return MHD_action_abort_request (request);
- }
- json_len = strlen (json_str);
- /* try to compress the body */
- is_compressed = MHD_NO;
- if (TALER_MHD2_can_compress (request))
- is_compressed = TALER_MHD2_body_compress (&json_str,
- &json_len);
- response = MHD_response_from_buffer (sc,
- json_len,
- json_str,
- &free,
- json_str);
- if (NULL == response)
- {
- free (json_str);
- GNUNET_break (0);
- return MHD_action_abort_request (request);
- }
- TALER_MHD2_add_global_headers (response,
- false);
- GNUNET_break (MHD_SC_OK ==
- MHD_response_add_header (response,
- MHD_HTTP_HEADER_CONTENT_TYPE,
- "application/json"));
- if (is_compressed)
- {
- /* Need to indicate to client that body is compressed */
- if (MHD_SC_OK !=
- MHD_response_add_header (response,
- MHD_HTTP_HEADER_CONTENT_ENCODING,
- "deflate"))
- {
- GNUNET_break (0);
- MHD_response_destroy (response);
- return MHD_action_abort_request (request);
- }
- }
-
- return MHD_action_from_response (request,
- response);
-}
-
-
-const struct MHD_Action *
-TALER_MHD2_reply_json_steal (struct MHD_Request *request,
- json_t *json,
- enum MHD_HTTP_StatusCode sc)
-{
- const struct MHD_Action *ret;
-
- ret = TALER_MHD2_reply_json (request,
- json,
- sc);
- json_decref (json);
- return ret;
-}
-
-
-const struct MHD_Action *
-TALER_MHD2_reply_cors_preflight (struct MHD_Request *request)
-{
- struct MHD_Response *response;
-
- response = MHD_response_from_empty (MHD_HTTP_STATUS_NO_CONTENT);
- if (NULL == response)
- return MHD_action_abort_request (request);
- /* This adds the Access-Control-Allow-Origin header.
- * All endpoints of the exchange allow CORS. */
- TALER_MHD2_add_global_headers (response,
- true);
- GNUNET_break (MHD_SC_OK ==
- MHD_response_add_header (response,
- /* Not available as MHD constant yet */
- "Access-Control-Allow-Headers",
- "*"));
- GNUNET_break (MHD_SC_OK ==
- MHD_response_add_header (response,
- /* Not available as MHD constant yet */
- "Access-Control-Allow-Methods",
- "*"));
- return MHD_action_from_response (request,
- response);
-}
-
-
-struct MHD_Response *
-TALER_MHD2_make_error (enum TALER_ErrorCode ec,
- const char *detail)
-{
- return TALER_MHD2_MAKE_JSON_PACK (
- TALER_ErrorCode_get_http_status (ec),
- TALER_MHD2_PACK_EC (ec),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_string ("detail", detail)));
-}
-
-
-const struct MHD_Action *
-TALER_MHD2_reply_with_error (struct MHD_Request *request,
- enum MHD_HTTP_StatusCode sc,
- enum TALER_ErrorCode ec,
- const char *detail)
-{
- return TALER_MHD2_REPLY_JSON_PACK (
- request,
- sc,
- TALER_MHD2_PACK_EC (ec),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_string ("detail", detail)));
-}
-
-
-const struct MHD_Action *
-TALER_MHD2_reply_with_ec (struct MHD_Request *request,
- enum TALER_ErrorCode ec,
- const char *detail)
-{
- unsigned int hc
- = TALER_ErrorCode_get_http_status (ec);
-
- if ( (0 == hc) ||
- (UINT_MAX == hc) )
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Invalid Taler error code %u provided for response!\n",
- (unsigned int) ec);
- hc = MHD_HTTP_STATUS_INTERNAL_SERVER_ERROR;
- }
- return TALER_MHD2_reply_with_error (request,
- (enum MHD_HTTP_StatusCode) hc,
- ec,
- detail);
-}
-
-
-const struct MHD_Action *
-TALER_MHD2_reply_request_too_large (struct MHD_Request *request)
-{
- return TALER_MHD2_reply_with_error (
- request,
- MHD_HTTP_STATUS_CONTENT_TOO_LARGE,
- TALER_EC_GENERIC_UPLOAD_EXCEEDS_LIMIT,
- NULL);
-}
-
-
-const struct MHD_Action *
-TALER_MHD2_reply_agpl (struct MHD_Request *request,
- const char *url)
-{
- const char *agpl =
- "This server is licensed under the Affero GPL. You will now be redirected to the source code.";
- struct MHD_Response *response;
-
- response = MHD_response_from_buffer_static (MHD_HTTP_STATUS_FOUND,
- strlen (agpl),
- (void *) agpl);
- if (NULL == response)
- {
- GNUNET_break (0);
- return MHD_action_abort_request (request);
- }
- TALER_MHD2_add_global_headers (response,
- true);
- GNUNET_break (MHD_SC_OK ==
- MHD_response_add_header (response,
- MHD_HTTP_HEADER_CONTENT_TYPE,
- "text/plain"));
- if (MHD_SC_OK !=
- MHD_response_add_header (response,
- MHD_HTTP_HEADER_LOCATION,
- url))
- {
- GNUNET_break (0);
- MHD_response_destroy (response);
- return MHD_action_abort_request (request);
- }
- return MHD_action_from_response (request,
- response);
-}
-
-
-const struct MHD_Action *
-TALER_MHD2_reply_static (struct MHD_Request *request,
- enum MHD_HTTP_StatusCode sc,
- const char *mime_type,
- const char *body,
- size_t body_size)
-{
- struct MHD_Response *response;
-
- response = MHD_response_from_buffer_static (sc,
- body_size,
- body);
- if (NULL == response)
- {
- GNUNET_break (0);
- return MHD_action_abort_request (request);
- }
- TALER_MHD2_add_global_headers (response,
- true);
- if (NULL != mime_type)
- GNUNET_break (MHD_SC_OK ==
- MHD_response_add_header (response,
- MHD_HTTP_HEADER_CONTENT_TYPE,
- mime_type));
- return MHD_action_from_response (request,
- response);
-}
-
-
-void
-TALER_MHD2_get_date_string (struct GNUNET_TIME_Absolute at,
- char date[128])
-{
- static const char *const days[] =
- { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
- static const char *const mons[] =
- { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
- "Nov", "Dec"};
- struct tm now;
- time_t t;
-#if ! defined(HAVE_C11_GMTIME_S) && ! defined(HAVE_W32_GMTIME_S) && \
- ! defined(HAVE_GMTIME_R)
- struct tm*pNow;
-#endif
-
- date[0] = 0;
- t = (time_t) (at.abs_value_us / 1000LL / 1000LL);
-#if defined(HAVE_C11_GMTIME_S)
- if (NULL == gmtime_s (&t, &now))
- return;
-#elif defined(HAVE_W32_GMTIME_S)
- if (0 != gmtime_s (&now, &t))
- return;
-#elif defined(HAVE_GMTIME_R)
- if (NULL == gmtime_r (&t, &now))
- return;
-#else
- pNow = gmtime (&t);
- if (NULL == pNow)
- return;
- now = *pNow;
-#endif
- sprintf (date,
- "%3s, %02u %3s %04u %02u:%02u:%02u GMT",
- days[now.tm_wday % 7],
- (unsigned int) now.tm_mday,
- mons[now.tm_mon % 12],
- (unsigned int) (1900 + now.tm_year),
- (unsigned int) now.tm_hour,
- (unsigned int) now.tm_min,
- (unsigned int) now.tm_sec);
-}
-
-
-/* end of mhd_responses.c */
diff --git a/src/mhd/mhd2_run.c b/src/mhd/mhd2_run.c
@@ -1,414 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2019-2025 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU Affero General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file mhd2_run.c
- * @brief API for running an MHD daemon with the
- * GNUnet scheduler
- * @author Christian Grothoff
- */
-#include <gnunet/gnunet_util_lib.h>
-#include <jansson.h>
-#define MHD_APP_SOCKET_CNTX_TYPE struct SocketContext
-#include <microhttpd2.h>
-#include "taler/taler_mhd2_lib.h"
-
-
-/**
- * Context to track whatever MHD wants us to wait for.
- */
-struct SocketContext
-{
- /**
- * Task for this socket.
- */
- struct GNUNET_SCHEDULER_Task *mhd_rtask;
-
- /**
- * Task for this socket.
- */
- struct GNUNET_SCHEDULER_Task *mhd_wtask;
-
- /**
- * Internal handle to pass to MHD when ready.
- */
- struct MHD_EventUpdateContext *ecb_cntx;
-
- /**
- * Socket to watch for.
- */
- struct GNUNET_NETWORK_Handle *fd;
-
- /**
- * Daemon this socket is about.
- */
- struct DaemonEntry *de;
-};
-
-
-/**
- * Entry in list of HTTP servers we are running.
- */
-struct DaemonEntry
-{
- /**
- * Kept in a DLL.
- */
- struct DaemonEntry *next;
-
- /**
- * Kept in a DLL.
- */
- struct DaemonEntry *prev;
-
- /**
- * The actual daemon.
- */
- struct MHD_Daemon *mhd;
-
- /**
- * Task running the HTTP server.
- */
- struct GNUNET_SCHEDULER_Task *mhd_task;
-
- /**
- * Task waiting for timeout on the HTTP server.
- */
- struct GNUNET_SCHEDULER_Task *timeout_task;
-
- /**
- * Set to true if we should immediately MHD_run() again.
- */
- bool triggered;
-
-};
-
-
-/**
- * Head of list of HTTP servers.
- */
-static struct DaemonEntry *mhd_head;
-
-/**
- * Tail of list of HTTP servers.
- */
-static struct DaemonEntry *mhd_tail;
-
-
-/**
- * Function that queries MHD's select sets and
- * starts the task waiting for them.
- *
- * @param[in,out] de daemon to start tasks for
- */
-static void
-prepare_daemon (struct DaemonEntry *de);
-
-
-/**
- * Trigger MHD on timeout.
- *
- * @param cls a `struct DaemonEntry`
- */
-static void
-handle_timeout (void *cls)
-{
- struct DaemonEntry *de = cls;
-
- de->timeout_task = NULL;
- prepare_daemon (de);
-}
-
-
-static void
-prepare_daemon (struct DaemonEntry *de)
-{
- uint_fast64_t next_max_wait;
- enum MHD_StatusCode sc;
-
- sc = MHD_daemon_process_reg_events (de->mhd,
- &next_max_wait);
- if (MHD_SC_OK != sc)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "MHD_daemon_process_reg_events failed: %d\n",
- (int) sc);
- return;
- }
- if (MHD_WAIT_INDEFINITELY == next_max_wait)
- return;
- de->timeout_task
- = GNUNET_SCHEDULER_add_delayed (
- GNUNET_TIME_relative_multiply (
- GNUNET_TIME_UNIT_MICROSECONDS,
- next_max_wait),
- &handle_timeout,
- de);
-}
-
-
-/**
- * Call MHD to process pending requests and then go back
- * and schedule the next run.
- *
- * @param cls our `struct DaemonEntry *`
- */
-static void
-run_daemon (void *cls)
-{
- struct DaemonEntry *de = cls;
-
- de->mhd_task = NULL;
- prepare_daemon (de);
-}
-
-
-/**
- * Called whenever MHD should process read-events on the socket.
- *
- * @param cls a `struct SocketContext`
- */
-static void
-mhd_rready (void *cls)
-{
- struct SocketContext *sc = cls;
- struct DaemonEntry *de = sc->de;
-
- sc->mhd_rtask = NULL;
- MHD_daemon_event_update (de->mhd,
- sc->ecb_cntx,
- MHD_FD_STATE_RECV);
- if (NULL != de->mhd_task)
- GNUNET_SCHEDULER_cancel (de->mhd_task);
- de->mhd_task = GNUNET_SCHEDULER_add_now (&run_daemon,
- de);
-}
-
-
-/**
- * Called whenever MHD should process write-events on the socket.
- *
- * @param cls a `struct SocketContext`
- */
-static void
-mhd_wready (void *cls)
-{
- struct SocketContext *sc = cls;
- struct DaemonEntry *de = sc->de;
-
- sc->mhd_wtask = NULL;
- MHD_daemon_event_update (de->mhd,
- sc->ecb_cntx,
- MHD_FD_STATE_SEND);
- if (NULL != de->mhd_task)
- GNUNET_SCHEDULER_cancel (de->mhd_task);
- de->mhd_task = GNUNET_SCHEDULER_add_now (&run_daemon,
- de);
-}
-
-
-/**
- * Callback for registration/de-registration of the sockets to watch.
- *
- * @param cls our `struct DaemonEntry`
- * @param fd the socket to watch
- * @param watch_for the states of the @a fd to watch, if set to
- * #MHD_FD_STATE_NONE the socket must be de-registred
- * @param app_cntx_old the old application defined context for the socket,
- * NULL if @a fd socket was not registered before
- * @param ecb_cntx the context handle to be used
- * with #MHD_daemon_event_update()
- * @return NULL if error (to connection will be aborted),
- * or the new socket context
- */
-static MHD_APP_SOCKET_CNTX_TYPE *
-socket_registration_update (
- void *cls,
- MHD_Socket fd,
- enum MHD_FdState watch_for,
- MHD_APP_SOCKET_CNTX_TYPE *app_cntx_old,
- struct MHD_EventUpdateContext *ecb_cntx)
-{
- struct DaemonEntry *de = cls;
-
- if (NULL == app_cntx_old)
- {
- app_cntx_old = GNUNET_new (struct SocketContext);
- app_cntx_old->ecb_cntx = ecb_cntx;
- app_cntx_old->fd = GNUNET_NETWORK_socket_box_native (fd);
- app_cntx_old->de = de;
- }
- if (MHD_FD_STATE_NONE == watch_for)
- {
- if (NULL != app_cntx_old->mhd_rtask)
- GNUNET_SCHEDULER_cancel (app_cntx_old->mhd_rtask);
- if (NULL != app_cntx_old->mhd_wtask)
- GNUNET_SCHEDULER_cancel (app_cntx_old->mhd_wtask);
- GNUNET_NETWORK_socket_free_memory_only_ (app_cntx_old->fd);
- GNUNET_free (app_cntx_old);
- return NULL;
- }
- if ( (MHD_FD_STATE_RECV & watch_for) &&
- (NULL == app_cntx_old->mhd_rtask) )
- {
- app_cntx_old->mhd_rtask
- = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
- app_cntx_old->fd,
- &mhd_rready,
- app_cntx_old);
- }
- if ( (MHD_FD_STATE_SEND & watch_for) &&
- (NULL == app_cntx_old->mhd_wtask) )
- {
- app_cntx_old->mhd_wtask
- = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
- app_cntx_old->fd,
- &mhd_wready,
- app_cntx_old);
- }
- if ( (0 == (MHD_FD_STATE_RECV & watch_for)) &&
- (NULL != app_cntx_old->mhd_rtask) )
- {
- GNUNET_SCHEDULER_cancel (app_cntx_old->mhd_rtask);
- app_cntx_old->mhd_rtask = NULL;
- }
- if ( (0 == (MHD_FD_STATE_SEND & watch_for)) &&
- (NULL != app_cntx_old->mhd_wtask) )
- {
- GNUNET_SCHEDULER_cancel (app_cntx_old->mhd_wtask);
- app_cntx_old->mhd_wtask = NULL;
- }
- return app_cntx_old;
-}
-
-
-void
-TALER_MHD2_daemon_start (struct MHD_Daemon *daemon)
-{
- struct DaemonEntry *de;
- enum MHD_StatusCode sc;
-
- de = GNUNET_new (struct DaemonEntry);
- GNUNET_assert (MHD_SC_OK ==
- MHD_DAEMON_SET_OPTIONS (
- daemon,
- MHD_D_OPTION_REREGISTER_ALL (true),
- MHD_D_OPTION_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL (
- &socket_registration_update,
- de)));
- de->mhd = daemon;
- sc = MHD_daemon_start (de->mhd);
- if (MHD_SC_OK != sc)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "MHD_daemon_start failed: %d\n",
- (int) sc);
- GNUNET_free (de);
- return;
- }
- GNUNET_CONTAINER_DLL_insert (mhd_head,
- mhd_tail,
- de);
- prepare_daemon (de);
-}
-
-
-void
-TALER_MHD2_daemons_halt (void)
-{
- for (struct DaemonEntry *de = mhd_head;
- NULL != de;
- de = de->next)
- {
- if (NULL != de->mhd_task)
- {
- GNUNET_SCHEDULER_cancel (de->mhd_task);
- de->mhd_task = NULL;
- }
- de->triggered = false;
- }
-}
-
-
-void
-TALER_MHD2_daemons_quiesce (void)
-{
- for (struct DaemonEntry *de = mhd_head;
- NULL != de;
- de = de->next)
- {
-#if FIXME_MHD2
- int fd;
-#endif
-
- if (NULL != de->mhd_task)
- {
- GNUNET_SCHEDULER_cancel (de->mhd_task);
- de->mhd_task = NULL;
- }
- de->triggered = false;
-#if FIXME_MHD2
- fd = MHD_daemon_quiesce (de->mhd);
- GNUNET_break (0 == close (fd));
-#endif
- }
-}
-
-
-void
-TALER_MHD2_daemons_destroy (void)
-{
- struct DaemonEntry *de;
-
- while (NULL != (de = mhd_head))
- {
- struct MHD_Daemon *mhd = de->mhd;
-
- if (NULL != de->mhd_task)
- {
- GNUNET_SCHEDULER_cancel (de->mhd_task);
- de->mhd_task = NULL;
- }
- MHD_daemon_destroy (mhd);
- GNUNET_CONTAINER_DLL_remove (mhd_head,
- mhd_tail,
- de);
- GNUNET_free (de);
- }
-}
-
-
-void
-TALER_MHD2_daemons_trigger (void)
-{
- for (struct DaemonEntry *de = mhd_head;
- NULL != de;
- de = de->next)
- {
- if (NULL != de->mhd_task)
- {
- GNUNET_SCHEDULER_cancel (de->mhd_task);
- de->mhd_task = GNUNET_SCHEDULER_add_now (&run_daemon,
- de);
- }
- else
- {
- de->triggered = true;
- }
- }
-}
-
-
-/* end of mhd2_run.c */
diff --git a/src/mhd/mhd2_spa.c b/src/mhd/mhd2_spa.c
@@ -1,390 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2020--2025 Taler Systems SA
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of EXCHANGEABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-*/
-/**
- * @file mhd2_spa.c
- * @brief logic to load single page apps
- * @author Christian Grothoff
- */
-#include "platform.h" /* UNNECESSARY? */
-#include <gnunet/gnunet_util_lib.h>
-#include "taler/taler_util.h"
-#include "taler/taler_mhd2_lib.h"
-
-
-/**
- * Resource from the WebUi.
- */
-struct WebuiFile
-{
- /**
- * Kept in a DLL.
- */
- struct WebuiFile *next;
-
- /**
- * Kept in a DLL.
- */
- struct WebuiFile *prev;
-
- /**
- * Path this resource matches.
- */
- char *path;
-
- /**
- * SPA resource, compressed.
- */
- struct MHD_Response *zresponse;
-
- /**
- * SPA resource, vanilla.
- */
- struct MHD_Response *response;
-
-};
-
-
-/**
- * Resource from the WebUi.
- */
-struct TALER_MHD2_Spa
-{
- /**
- * Resources of the WebUI, kept in a DLL.
- */
- struct WebuiFile *webui_head;
-
- /**
- * Resources of the WebUI, kept in a DLL.
- */
- struct WebuiFile *webui_tail;
-};
-
-
-const struct MHD_Action *
-TALER_MHD2_spa_handler (const struct TALER_MHD2_Spa *spa,
- struct MHD_Request *request,
- const char *path)
-{
- struct WebuiFile *w = NULL;
-
- if ( (NULL == path) ||
- (0 == strcmp (path,
- "")) )
- path = "index.html";
- for (struct WebuiFile *pos = spa->webui_head;
- NULL != pos;
- pos = pos->next)
- if (0 == strcmp (path,
- pos->path))
- {
- w = pos;
- break;
- }
- if (NULL == w)
- return TALER_MHD2_reply_with_error (request,
- MHD_HTTP_STATUS_NOT_FOUND,
- TALER_EC_GENERIC_ENDPOINT_UNKNOWN,
- path);
- if ( (MHD_YES ==
- TALER_MHD2_can_compress (request)) &&
- (NULL != w->zresponse) )
- return MHD_action_from_response (request,
- w->zresponse);
- return MHD_action_from_response (request,
- w->response);
-}
-
-
-/**
- * Function called on each file to load for the WebUI.
- *
- * @param cls the `struct TALER_MHD2_Spa *` to build
- * @param dn name of the file to load
- */
-static enum GNUNET_GenericReturnValue
-build_webui (void *cls,
- const char *dn)
-{
- static const struct
- {
- const char *ext;
- const char *mime;
- } mime_map[] = {
- {
- .ext = "css",
- .mime = "text/css"
- },
- {
- .ext = "html",
- .mime = "text/html"
- },
- {
- .ext = "js",
- .mime = "text/javascript"
- },
- {
- .ext = "jpg",
- .mime = "image/jpeg"
- },
- {
- .ext = "jpeg",
- .mime = "image/jpeg"
- },
- {
- .ext = "png",
- .mime = "image/png"
- },
- {
- .ext = "svg",
- .mime = "image/svg+xml"
- },
- {
- .ext = NULL,
- .mime = NULL
- },
- };
- struct TALER_MHD2_Spa *spa = cls;
- int fd;
- struct stat sb;
- struct MHD_Response *zresponse = NULL;
- struct MHD_Response *response;
- const char *ext;
- const char *mime;
-
- fd = open (dn,
- O_RDONLY);
- if (-1 == fd)
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
- "open",
- dn);
- return GNUNET_SYSERR;
- }
- if (0 !=
- fstat (fd,
- &sb))
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
- "open",
- dn);
- GNUNET_break (0 == close (fd));
- return GNUNET_SYSERR;
- }
-
- mime = NULL;
- ext = strrchr (dn, '.');
- if (NULL == ext)
- {
- GNUNET_break (0 == close (fd));
- return GNUNET_OK;
- }
- ext++;
- for (unsigned int i = 0; NULL != mime_map[i].ext; i++)
- if (0 == strcasecmp (ext,
- mime_map[i].ext))
- {
- mime = mime_map[i].mime;
- break;
- }
-
- {
- void *in;
- ssize_t r;
- size_t csize;
-
- in = GNUNET_malloc_large (sb.st_size);
- if (NULL == in)
- {
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
- "malloc");
- GNUNET_break (0 == close (fd));
- return GNUNET_SYSERR;
- }
- r = read (fd,
- in,
- sb.st_size);
- if ( (-1 == r) ||
- (sb.st_size != (size_t) r) )
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
- "read",
- dn);
- GNUNET_free (in);
- GNUNET_break (0 == close (fd));
- return GNUNET_SYSERR;
- }
- csize = (size_t) r;
- if (TALER_MHD2_body_compress (&in,
- &csize))
- {
- zresponse = MHD_response_from_buffer (MHD_HTTP_STATUS_OK,
- csize,
- in,
- &free,
- in);
- if (NULL != zresponse)
- {
- if (MHD_SC_OK !=
- MHD_response_add_header (zresponse,
- MHD_HTTP_HEADER_CONTENT_ENCODING,
- "deflate"))
- {
- GNUNET_break (0);
- MHD_response_destroy (zresponse);
- zresponse = NULL;
- }
- else if (NULL != mime)
- GNUNET_break (MHD_SC_OK ==
- MHD_response_add_header (zresponse,
- MHD_HTTP_HEADER_CONTENT_TYPE,
- mime));
- /* Which representation we return depends on the
- Accept-Encoding header of the client, so shared caches
- must not serve one variant to a client that asked for
- another. */
- if (NULL != zresponse)
- GNUNET_break (MHD_SC_OK ==
- MHD_response_add_header (zresponse,
- MHD_HTTP_HEADER_VARY,
- MHD_HTTP_HEADER_ACCEPT_ENCODING));
- }
- }
- else
- {
- GNUNET_free (in);
- }
- }
-
- response = MHD_response_from_fd (MHD_HTTP_STATUS_OK,
- fd,
- 0LLU,
- sb.st_size);
- if (NULL == response)
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
- "open",
- dn);
- GNUNET_break (0 == close (fd));
- if (NULL != zresponse)
- {
- MHD_response_destroy (zresponse);
- zresponse = NULL;
- }
- return GNUNET_SYSERR;
- }
- if (NULL != mime)
- GNUNET_break (MHD_SC_OK ==
- MHD_response_add_header (response,
- MHD_HTTP_HEADER_CONTENT_TYPE,
- mime));
- GNUNET_break (MHD_SC_OK ==
- MHD_response_add_header (response,
- MHD_HTTP_HEADER_VARY,
- MHD_HTTP_HEADER_ACCEPT_ENCODING));
-
- {
- struct WebuiFile *w;
- const char *fn;
-
- fn = strrchr (dn, '/');
- GNUNET_assert (NULL != fn);
- w = GNUNET_new (struct WebuiFile);
- w->path = GNUNET_strdup (fn + 1);
- w->response = response;
- w->zresponse = zresponse;
- GNUNET_assert (MHD_SC_OK ==
- MHD_RESPONSE_SET_OPTIONS (response,
- MHD_R_OPTION_REUSABLE (MHD_YES)));
- if (NULL != zresponse)
- GNUNET_assert (MHD_SC_OK ==
- MHD_RESPONSE_SET_OPTIONS (zresponse,
- MHD_R_OPTION_REUSABLE (MHD_YES)))
- ;
- GNUNET_CONTAINER_DLL_insert (spa->webui_head,
- spa->webui_tail,
- w);
- }
- return GNUNET_OK;
-}
-
-
-struct TALER_MHD2_Spa *
-TALER_MHD2_spa_load (const struct GNUNET_OS_ProjectData *pd,
- const char *dir)
-{
- struct TALER_MHD2_Spa *spa;
- char *dn;
-
- {
- char *path;
-
- path = GNUNET_OS_installation_get_path (pd,
- GNUNET_OS_IPK_DATADIR);
- if (NULL == path)
- {
- GNUNET_break (0);
- return NULL;
- }
- GNUNET_asprintf (&dn,
- "%s%s",
- path,
- dir);
- GNUNET_free (path);
- }
- spa = GNUNET_new (struct TALER_MHD2_Spa);
- if (-1 ==
- GNUNET_DISK_directory_scan (dn,
- &build_webui,
- spa))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to load WebUI from `%s'\n",
- dn);
- GNUNET_free (dn);
- TALER_MHD2_spa_free (spa);
- return NULL;
- }
- GNUNET_free (dn);
- return spa;
-}
-
-
-void
-TALER_MHD2_spa_free (struct TALER_MHD2_Spa *spa)
-{
- struct WebuiFile *w;
-
- while (NULL != (w = spa->webui_head))
- {
- GNUNET_CONTAINER_DLL_remove (spa->webui_head,
- spa->webui_tail,
- w);
- if (NULL != w->response)
- {
- MHD_response_destroy (w->response);
- w->response = NULL;
- }
- if (NULL != w->zresponse)
- {
- MHD_response_destroy (w->zresponse);
- w->zresponse = NULL;
- }
- GNUNET_free (w->path);
- GNUNET_free (w);
- }
- GNUNET_free (spa);
-}