commit 13e058a902a3dbee9d7fe327030b88c2d126675b
parent 5e715eabb211fc9310ae7ccf0419267699a3f5dc
Author: Christian Grothoff <christian@grothoff.org>
Date: Sun, 2 Mar 2025 00:53:00 +0100
update to match latest GNUnet APIs, begin work on libtalermhd2
Diffstat:
28 files changed, 2111 insertions(+), 486 deletions(-)
diff --git a/README b/README
@@ -60,7 +60,7 @@ Direct dependencies
These are the direct dependencies for running a Taler exchange:
-- GNUnet >= 0.23.0
+- GNUnet >= 0.23.3
- GNU libmicrohttpd >= 0.9.71
- PostgreSQL >= 15.0
diff --git a/configure.ac b/configure.ac
@@ -143,7 +143,7 @@ AS_CASE([$with_microhttpd],
MHD_VERSION_AT_LEAST([0.9.71])
-# check for libmicrohttpd
+# check for libmicrohttpd2
AC_MSG_CHECKING([for microhttpd2])
AC_ARG_WITH([microhttpd2],
[AS_HELP_STRING([--with-microhttpd2=PFX], [base of libmicrohttpd2 installation])],
@@ -151,8 +151,8 @@ AC_ARG_WITH([microhttpd2],
[AC_MSG_RESULT([not given])
with_microhttpd2=yes])
AS_CASE([$with_microhttpd2],
- [yes],,
- [no],,
+ [yes],[],
+ [no],[],
[LDFLAGS="-L$with_microhttpd2/lib $LDFLAGS"
CPPFLAGS="-I$with_microhttpd2/include $CPPFLAGS"])
MHD2_VERSION_AT_LEAST([1.99.0])
@@ -198,15 +198,15 @@ AC_CHECK_HEADERS([gnunet/gnunet_util_lib.h],
AS_IF([test $libgnunetutil != 1],
[AC_MSG_ERROR([[
***
-*** You need libgnunetutil >= 0.21.1 to build this program.
+*** You need libgnunetutil >= 0.23.3 to build this program.
*** This library is part of GNUnet, available at
*** https://gnunet.org
*** ]])])
-# Check for GNUnet's libgnunetjson.
+# Check for GNUnet's libgnunetmhd.
libgnunetjson=0
-AC_MSG_CHECKING([for libgnunetjson])
+AC_MSG_CHECKING([for libgnunetmhd])
AC_ARG_WITH(gnunet,
[AS_HELP_STRING([--with-gnunet=PFX], [base of GNUnet installation])],
[AC_MSG_RESULT([given as $with_gnunet])],
@@ -217,14 +217,15 @@ AS_CASE([$with_gnunet],
[no], [AC_MSG_ERROR([--with-gnunet is required])],
[LDFLAGS="-L$with_gnunet/lib $LDFLAGS"
CPPFLAGS="-I$with_gnunet/include $CPPFLAGS"])
-AC_CHECK_HEADERS([gnunet/gnunet_json_lib.h],
- [AC_CHECK_LIB([gnunetjson], [GNUNET_JSON_parse], libgnunetjson=1)])
-AS_IF([test $libgnunetjson != 1],
+AC_CHECK_HEADERS([gnunet/gnunet_mhd_lib.h],
+ [AC_CHECK_LIB([gnunetmhd], [GNUNET_MHD_parse], libgnunetmhd=1)])
+AS_IF([test $libgnunetmhd != 1],
[AC_MSG_ERROR([[
***
-*** You need libgnunetjson to build this program.
-*** Make sure you have libjansson installed while
-*** building GNUnet.
+*** You need GNUnet >= 0.23.3 to build this program.
+*** You need libgnunetmhd to build this program.
+*** Make sure you have libmicrohttpd and libjansson
+*** installed while building GNUnet.
*** ]])])
# check for gettext
diff --git a/contrib/microhttpd.tag b/contrib/microhttpd.tag
@@ -1,7 +1,23 @@
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<tagfile>
<compound kind="file">
- <name>microhttpd_lib.h</name>
+ <name>microhttpd2.h</name>
+ <path></path>
+ <member kind="define">
+ <type>#define</type>
+ <name>MHD_FD_STATE_NONE</name>
+ <anchorfile>microhttpd2.h</anchorfile>
+ <arglist></arglist>
+ </member>
+ <member kind="function">
+ <type>#define</type>
+ <name>MHD_daemon_event_update</name>
+ <anchorfile>microhttpd2.h</anchorfile>
+ <arglist></arglist>
+ </member>
+ </compound>
+ <compound kind="file">
+ <name>microhttpd.h</name>
<path></path>
<filename>microhttpd.h</filename>
<member kind="define">
diff --git a/src/bank-lib/Makefile.am b/src/bank-lib/Makefile.am
@@ -51,6 +51,7 @@ libtalerbank_la_LIBADD = \
$(top_builddir)/src/util/libtalerutil.la \
-lgnunetcurl \
-lgnunetjson \
+ -lgnunetmhd \
-lgnunetutil \
-ljansson \
-lcurl \
diff --git a/src/bank-lib/fakebank_bank_post_accounts_token.c b/src/bank-lib/fakebank_bank_post_accounts_token.c
@@ -27,6 +27,7 @@
#include "taler_bank_service.h"
#include "taler_mhd_lib.h"
#include <gnunet/gnunet_mhd_compat.h>
+#include <gnunet/gnunet_mhd_lib.h>
#include "fakebank.h"
#include "fakebank_bank_post_accounts_token.h"
#include "fakebank_common_lookup.h"
@@ -118,36 +119,36 @@ TALER_FAKEBANK_bank_post_accounts_token_ (
void **con_cls)
{
struct ConnectionContext *cc = *con_cls;
- enum GNUNET_JSON_PostResult pr;
+ enum GNUNET_MHD_PostResult pr;
json_t *json;
MHD_RESULT res;
if (NULL == cc)
{
cc = GNUNET_new (struct ConnectionContext);
- cc->ctx_cleaner = &GNUNET_JSON_post_parser_cleanup;
+ cc->ctx_cleaner = &GNUNET_MHD_post_parser_cleanup;
*con_cls = cc;
}
- pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX,
- connection,
- &cc->ctx,
- upload_data,
- upload_data_size,
- &json);
+ pr = GNUNET_MHD_post_parser (REQUEST_BUFFER_MAX,
+ connection,
+ &cc->ctx,
+ upload_data,
+ upload_data_size,
+ &json);
switch (pr)
{
- case GNUNET_JSON_PR_OUT_OF_MEMORY:
+ case GNUNET_MHD_PR_OUT_OF_MEMORY:
GNUNET_break (0);
return MHD_NO;
- case GNUNET_JSON_PR_CONTINUE:
+ case GNUNET_MHD_PR_CONTINUE:
return MHD_YES;
- case GNUNET_JSON_PR_REQUEST_TOO_LARGE:
+ case GNUNET_MHD_PR_REQUEST_TOO_LARGE:
GNUNET_break (0);
return MHD_NO;
- case GNUNET_JSON_PR_JSON_INVALID:
+ case GNUNET_MHD_PR_JSON_INVALID:
GNUNET_break (0);
return MHD_NO;
- case GNUNET_JSON_PR_SUCCESS:
+ case GNUNET_MHD_PR_SUCCESS:
break;
}
diff --git a/src/bank-lib/fakebank_bank_post_accounts_withdrawals.c b/src/bank-lib/fakebank_bank_post_accounts_withdrawals.c
@@ -27,6 +27,7 @@
#include "taler_bank_service.h"
#include "taler_mhd_lib.h"
#include <gnunet/gnunet_mhd_compat.h>
+#include <gnunet/gnunet_mhd_lib.h>
#include "fakebank.h"
#include "fakebank_bank_post_accounts_withdrawals.h"
#include "fakebank_common_lookup.h"
@@ -89,6 +90,7 @@ do_post_account_withdrawals (
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
+
break;
}
{
@@ -140,36 +142,36 @@ TALER_FAKEBANK_bank_post_account_withdrawals_ (
void **con_cls)
{
struct ConnectionContext *cc = *con_cls;
- enum GNUNET_JSON_PostResult pr;
+ enum GNUNET_MHD_PostResult pr;
json_t *json;
MHD_RESULT res;
if (NULL == cc)
{
cc = GNUNET_new (struct ConnectionContext);
- cc->ctx_cleaner = &GNUNET_JSON_post_parser_cleanup;
+ cc->ctx_cleaner = &GNUNET_MHD_post_parser_cleanup;
*con_cls = cc;
}
- pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX,
- connection,
- &cc->ctx,
- upload_data,
- upload_data_size,
- &json);
+ pr = GNUNET_MHD_post_parser (REQUEST_BUFFER_MAX,
+ connection,
+ &cc->ctx,
+ upload_data,
+ upload_data_size,
+ &json);
switch (pr)
{
- case GNUNET_JSON_PR_OUT_OF_MEMORY:
+ case GNUNET_MHD_PR_OUT_OF_MEMORY:
GNUNET_break (0);
return MHD_NO;
- case GNUNET_JSON_PR_CONTINUE:
+ case GNUNET_MHD_PR_CONTINUE:
return MHD_YES;
- case GNUNET_JSON_PR_REQUEST_TOO_LARGE:
+ case GNUNET_MHD_PR_REQUEST_TOO_LARGE:
GNUNET_break (0);
return MHD_NO;
- case GNUNET_JSON_PR_JSON_INVALID:
+ case GNUNET_MHD_PR_JSON_INVALID:
GNUNET_break (0);
return MHD_NO;
- case GNUNET_JSON_PR_SUCCESS:
+ case GNUNET_MHD_PR_SUCCESS:
break;
}
diff --git a/src/bank-lib/fakebank_bank_post_withdrawals_id_op.c b/src/bank-lib/fakebank_bank_post_withdrawals_id_op.c
@@ -27,6 +27,7 @@
#include "taler_bank_service.h"
#include "taler_mhd_lib.h"
#include <gnunet/gnunet_mhd_compat.h>
+#include <gnunet/gnunet_mhd_lib.h>
#include "fakebank.h"
#include "fakebank_bank_post_withdrawals_id_op.h"
#include "fakebank_common_lookup.h"
@@ -276,33 +277,33 @@ TALER_FAKEBANK_bank_withdrawals_id_op_ (
if (NULL == cc)
{
cc = GNUNET_new (struct ConnectionContext);
- cc->ctx_cleaner = &GNUNET_JSON_post_parser_cleanup;
+ cc->ctx_cleaner = &GNUNET_MHD_post_parser_cleanup;
*con_cls = cc;
}
if (0 != *upload_data_size)
{
- enum GNUNET_JSON_PostResult pr;
+ enum GNUNET_MHD_PostResult pr;
- pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX,
- connection,
- &cc->ctx,
- upload_data,
- upload_data_size,
- &json);
+ pr = GNUNET_MHD_post_parser (REQUEST_BUFFER_MAX,
+ connection,
+ &cc->ctx,
+ upload_data,
+ upload_data_size,
+ &json);
switch (pr)
{
- case GNUNET_JSON_PR_OUT_OF_MEMORY:
+ case GNUNET_MHD_PR_OUT_OF_MEMORY:
GNUNET_break (0);
return MHD_NO;
- case GNUNET_JSON_PR_CONTINUE:
+ case GNUNET_MHD_PR_CONTINUE:
return MHD_YES;
- case GNUNET_JSON_PR_REQUEST_TOO_LARGE:
+ case GNUNET_MHD_PR_REQUEST_TOO_LARGE:
GNUNET_break (0);
return MHD_NO;
- case GNUNET_JSON_PR_JSON_INVALID:
+ case GNUNET_MHD_PR_JSON_INVALID:
GNUNET_break (0);
return MHD_NO;
- case GNUNET_JSON_PR_SUCCESS:
+ case GNUNET_MHD_PR_SUCCESS:
break;
}
}
diff --git a/src/bank-lib/fakebank_bank_testing_register.c b/src/bank-lib/fakebank_bank_testing_register.c
@@ -26,6 +26,7 @@
#include "taler_bank_service.h"
#include "taler_mhd_lib.h"
#include <gnunet/gnunet_mhd_compat.h>
+#include <gnunet/gnunet_mhd_lib.h>
#include "fakebank.h"
#include "fakebank_bank_testing_register.h"
@@ -39,36 +40,36 @@ TALER_FAKEBANK_bank_testing_register_ (
void **con_cls)
{
struct ConnectionContext *cc = *con_cls;
- enum GNUNET_JSON_PostResult pr;
+ enum GNUNET_MHD_PostResult pr;
json_t *json;
MHD_RESULT res;
if (NULL == cc)
{
cc = GNUNET_new (struct ConnectionContext);
- cc->ctx_cleaner = &GNUNET_JSON_post_parser_cleanup;
+ cc->ctx_cleaner = &GNUNET_MHD_post_parser_cleanup;
*con_cls = cc;
}
- pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX,
- connection,
- &cc->ctx,
- upload_data,
- upload_data_size,
- &json);
+ pr = GNUNET_MHD_post_parser (REQUEST_BUFFER_MAX,
+ connection,
+ &cc->ctx,
+ upload_data,
+ upload_data_size,
+ &json);
switch (pr)
{
- case GNUNET_JSON_PR_OUT_OF_MEMORY:
+ case GNUNET_MHD_PR_OUT_OF_MEMORY:
GNUNET_break (0);
return MHD_NO;
- case GNUNET_JSON_PR_CONTINUE:
+ case GNUNET_MHD_PR_CONTINUE:
return MHD_YES;
- case GNUNET_JSON_PR_REQUEST_TOO_LARGE:
+ case GNUNET_MHD_PR_REQUEST_TOO_LARGE:
GNUNET_break (0);
return MHD_NO;
- case GNUNET_JSON_PR_JSON_INVALID:
+ case GNUNET_MHD_PR_JSON_INVALID:
GNUNET_break (0);
return MHD_NO;
- case GNUNET_JSON_PR_SUCCESS:
+ case GNUNET_MHD_PR_SUCCESS:
break;
}
diff --git a/src/bank-lib/fakebank_tbi_post_withdrawal_operation.c b/src/bank-lib/fakebank_tbi_post_withdrawal_operation.c
@@ -27,6 +27,7 @@
#include "taler_bank_service.h"
#include "taler_mhd_lib.h"
#include <gnunet/gnunet_mhd_compat.h>
+#include <gnunet/gnunet_mhd_lib.h>
#include "fakebank.h"
#include "fakebank_common_lookup.h"
#include "fakebank_tbi_post_withdrawal_operation.h"
@@ -205,36 +206,36 @@ TALER_FAKEBANK_tbi_post_withdrawal (
void **con_cls)
{
struct ConnectionContext *cc = *con_cls;
- enum GNUNET_JSON_PostResult pr;
+ enum GNUNET_MHD_PostResult pr;
json_t *json;
MHD_RESULT res;
if (NULL == cc)
{
cc = GNUNET_new (struct ConnectionContext);
- cc->ctx_cleaner = &GNUNET_JSON_post_parser_cleanup;
+ cc->ctx_cleaner = &GNUNET_MHD_post_parser_cleanup;
*con_cls = cc;
}
- pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX,
- connection,
- &cc->ctx,
- upload_data,
- upload_data_size,
- &json);
+ pr = GNUNET_MHD_post_parser (REQUEST_BUFFER_MAX,
+ connection,
+ &cc->ctx,
+ upload_data,
+ upload_data_size,
+ &json);
switch (pr)
{
- case GNUNET_JSON_PR_OUT_OF_MEMORY:
+ case GNUNET_MHD_PR_OUT_OF_MEMORY:
GNUNET_break (0);
return MHD_NO;
- case GNUNET_JSON_PR_CONTINUE:
+ case GNUNET_MHD_PR_CONTINUE:
return MHD_YES;
- case GNUNET_JSON_PR_REQUEST_TOO_LARGE:
+ case GNUNET_MHD_PR_REQUEST_TOO_LARGE:
GNUNET_break (0);
return MHD_NO;
- case GNUNET_JSON_PR_JSON_INVALID:
+ case GNUNET_MHD_PR_JSON_INVALID:
GNUNET_break (0);
return MHD_NO;
- case GNUNET_JSON_PR_SUCCESS:
+ case GNUNET_MHD_PR_SUCCESS:
break;
}
diff --git a/src/bank-lib/fakebank_twg_admin_add_incoming.c b/src/bank-lib/fakebank_twg_admin_add_incoming.c
@@ -26,6 +26,7 @@
#include "taler_bank_service.h"
#include "taler_mhd_lib.h"
#include <gnunet/gnunet_mhd_compat.h>
+#include <gnunet/gnunet_mhd_lib.h>
#include "fakebank.h"
#include "fakebank_common_make_admin_transfer.h"
#include "fakebank_twg_admin_add_incoming.h"
@@ -40,7 +41,7 @@ TALER_FAKEBANK_twg_admin_add_incoming_ (
void **con_cls)
{
struct ConnectionContext *cc = *con_cls;
- enum GNUNET_JSON_PostResult pr;
+ enum GNUNET_MHD_PostResult pr;
json_t *json;
uint64_t row_id;
struct GNUNET_TIME_Timestamp timestamp;
@@ -48,29 +49,29 @@ TALER_FAKEBANK_twg_admin_add_incoming_ (
if (NULL == cc)
{
cc = GNUNET_new (struct ConnectionContext);
- cc->ctx_cleaner = &GNUNET_JSON_post_parser_cleanup;
+ cc->ctx_cleaner = &GNUNET_MHD_post_parser_cleanup;
*con_cls = cc;
}
- pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX,
- connection,
- &cc->ctx,
- upload_data,
- upload_data_size,
- &json);
+ pr = GNUNET_MHD_post_parser (REQUEST_BUFFER_MAX,
+ connection,
+ &cc->ctx,
+ upload_data,
+ upload_data_size,
+ &json);
switch (pr)
{
- case GNUNET_JSON_PR_OUT_OF_MEMORY:
+ case GNUNET_MHD_PR_OUT_OF_MEMORY:
GNUNET_break (0);
return MHD_NO;
- case GNUNET_JSON_PR_CONTINUE:
+ case GNUNET_MHD_PR_CONTINUE:
return MHD_YES;
- case GNUNET_JSON_PR_REQUEST_TOO_LARGE:
+ case GNUNET_MHD_PR_REQUEST_TOO_LARGE:
GNUNET_break (0);
return MHD_NO;
- case GNUNET_JSON_PR_JSON_INVALID:
+ case GNUNET_MHD_PR_JSON_INVALID:
GNUNET_break (0);
return MHD_NO;
- case GNUNET_JSON_PR_SUCCESS:
+ case GNUNET_MHD_PR_SUCCESS:
break;
}
{
diff --git a/src/bank-lib/fakebank_twg_admin_add_kycauth.c b/src/bank-lib/fakebank_twg_admin_add_kycauth.c
@@ -26,6 +26,7 @@
#include "taler_bank_service.h"
#include "taler_mhd_lib.h"
#include <gnunet/gnunet_mhd_compat.h>
+#include <gnunet/gnunet_mhd_lib.h>
#include "fakebank.h"
#include "fakebank_common_make_admin_transfer.h"
#include "fakebank_twg_admin_add_kycauth.h"
@@ -41,7 +42,7 @@ TALER_FAKEBANK_twg_admin_add_kycauth_ (
void **con_cls)
{
struct ConnectionContext *cc = *con_cls;
- enum GNUNET_JSON_PostResult pr;
+ enum GNUNET_MHD_PostResult pr;
json_t *json;
uint64_t row_id;
struct GNUNET_TIME_Timestamp timestamp;
@@ -49,29 +50,29 @@ TALER_FAKEBANK_twg_admin_add_kycauth_ (
if (NULL == cc)
{
cc = GNUNET_new (struct ConnectionContext);
- cc->ctx_cleaner = &GNUNET_JSON_post_parser_cleanup;
+ cc->ctx_cleaner = &GNUNET_MHD_post_parser_cleanup;
*con_cls = cc;
}
- pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX,
- connection,
- &cc->ctx,
- upload_data,
- upload_data_size,
- &json);
+ pr = GNUNET_MHD_post_parser (REQUEST_BUFFER_MAX,
+ connection,
+ &cc->ctx,
+ upload_data,
+ upload_data_size,
+ &json);
switch (pr)
{
- case GNUNET_JSON_PR_OUT_OF_MEMORY:
+ case GNUNET_MHD_PR_OUT_OF_MEMORY:
GNUNET_break (0);
return MHD_NO;
- case GNUNET_JSON_PR_CONTINUE:
+ case GNUNET_MHD_PR_CONTINUE:
return MHD_YES;
- case GNUNET_JSON_PR_REQUEST_TOO_LARGE:
+ case GNUNET_MHD_PR_REQUEST_TOO_LARGE:
GNUNET_break (0);
return MHD_NO;
- case GNUNET_JSON_PR_JSON_INVALID:
+ case GNUNET_MHD_PR_JSON_INVALID:
GNUNET_break (0);
return MHD_NO;
- case GNUNET_JSON_PR_SUCCESS:
+ case GNUNET_MHD_PR_SUCCESS:
break;
}
{
diff --git a/src/bank-lib/fakebank_twg_transfer.c b/src/bank-lib/fakebank_twg_transfer.c
@@ -26,6 +26,7 @@
#include "taler_bank_service.h"
#include "taler_mhd_lib.h"
#include <gnunet/gnunet_mhd_compat.h>
+#include <gnunet/gnunet_mhd_lib.h>
#include "fakebank.h"
#include "fakebank_common_transact.h"
#include "fakebank_twg_transfer.h"
@@ -52,7 +53,7 @@ TALER_FAKEBANK_handle_transfer_ (
void **con_cls)
{
struct ConnectionContext *cc = *con_cls;
- enum GNUNET_JSON_PostResult pr;
+ enum GNUNET_MHD_PostResult pr;
json_t *json;
uint64_t row_id;
struct GNUNET_TIME_Timestamp ts;
@@ -60,29 +61,29 @@ TALER_FAKEBANK_handle_transfer_ (
if (NULL == cc)
{
cc = GNUNET_new (struct ConnectionContext);
- cc->ctx_cleaner = &GNUNET_JSON_post_parser_cleanup;
+ cc->ctx_cleaner = &GNUNET_MHD_post_parser_cleanup;
*con_cls = cc;
}
- pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX,
- connection,
- &cc->ctx,
- upload_data,
- upload_data_size,
- &json);
+ pr = GNUNET_MHD_post_parser (REQUEST_BUFFER_MAX,
+ connection,
+ &cc->ctx,
+ upload_data,
+ upload_data_size,
+ &json);
switch (pr)
{
- case GNUNET_JSON_PR_OUT_OF_MEMORY:
+ case GNUNET_MHD_PR_OUT_OF_MEMORY:
GNUNET_break (0);
return MHD_NO;
- case GNUNET_JSON_PR_CONTINUE:
+ case GNUNET_MHD_PR_CONTINUE:
return MHD_YES;
- case GNUNET_JSON_PR_REQUEST_TOO_LARGE:
+ case GNUNET_MHD_PR_REQUEST_TOO_LARGE:
GNUNET_break (0);
return MHD_NO;
- case GNUNET_JSON_PR_JSON_INVALID:
+ case GNUNET_MHD_PR_JSON_INVALID:
GNUNET_break (0);
return MHD_NO;
- case GNUNET_JSON_PR_SUCCESS:
+ case GNUNET_MHD_PR_SUCCESS:
break;
}
{
diff --git a/src/bank-lib/taler-exchange-wire-gateway-client.c b/src/bank-lib/taler-exchange-wire-gateway-client.c
@@ -22,6 +22,7 @@
#include <gnunet/gnunet_util_lib.h>
#include <gnunet/gnunet_json_lib.h>
#include <jansson.h>
+#include <microhttpd.h>
#include "taler_bank_service.h"
/**
diff --git a/src/exchange/taler-exchange-httpd_age-withdraw_reveal.c b/src/exchange/taler-exchange-httpd_age-withdraw_reveal.c
@@ -349,11 +349,11 @@ calculate_blinded_hash (
if (GNUNET_OK != ret)
{
GNUNET_break (0);
- *result = TALER_MHD_reply_json_pack (connection,
+ *result = TALER_MHD_REPLY_JSON_PACK (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
- "{ss}",
- "details",
- "failed to prepare planchet from base key");
+ GNUNET_JSON_pack_string (
+ "details",
+ "failed to prepare planchet from base key"));
return ret;
}
diff --git a/src/include/Makefile.am b/src/include/Makefile.am
@@ -31,6 +31,11 @@ talerinclude_HEADERS = \
taler_templating_lib.h \
taler_twister_testing_lib.h
+if HAVE_MHD2
+talerinclude_HEADERS += \
+ taler_mhd2_lib.h
+endif
+
EXTRA_DIST = \
backoff.h \
gauger.h
diff --git a/src/include/taler_kyclogic_plugin.h b/src/include/taler_kyclogic_plugin.h
@@ -22,6 +22,7 @@
#define TALER_KYCLOGIC_PLUGIN_H
#include <jansson.h>
+#include <microhttpd.h>
#include <gnunet/gnunet_util_lib.h>
#include <gnunet/gnunet_db_lib.h>
#include "taler_util.h"
diff --git a/src/include/taler_mhd2_lib.h b/src/include/taler_mhd2_lib.h
@@ -0,0 +1,1037 @@
+/*
+ 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_error_codes.h"
+#include "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
+
+};
+
+
+/**
+ * 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
+ */
+void
+TALER_MHD2_add_global_headers (struct MHD_Response *response);
+
+
+/**
+ * Try to compress a response body. Updates @a buf and @a buf_size.
+ *
+ * @param[in,out] buf pointer to body to compress
+ * @param[in,out] buf_size pointer to initial size of @a buf
+ * @return 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 ec error code uniquely identifying the error
+ * @param sc HTTP status code to use
+ * @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);
+
+
+#if FIXME
+
+/**
+ * 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)
+
+#endif
+
+
+/**
+ * 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)
+
+
+/**
+ * Parse the configuration to determine on which port
+ * or UNIX domain path we should run an HTTP service.
+ *
+ * @param cfg configuration to parse
+ * @param section section of the configuration to parse (usually "exchange")
+ * @param[out] rport set to the port number, or 0 for none
+ * @param[out] unix_path set to the UNIX path, or NULL for none
+ * @param[out] unix_mode set to the mode to be used for @a unix_path
+ * @return #GNUNET_OK on success
+ */
+enum GNUNET_GenericReturnValue
+TALER_MHD2_parse_config (const struct GNUNET_CONFIGURATION_Handle *cfg,
+ const char *section,
+ uint16_t *rport,
+ char **unix_path,
+ mode_t *unix_mode);
+
+
+/**
+ * Function called for logging by MHD.
+ *
+ * @param cls closure, NULL
+ * @param fm format string (`printf()`-style)
+ * @param ap arguments to @a fm
+ */
+void
+TALER_MHD2_handle_logs (void *cls,
+ const char *fm,
+ va_list ap);
+
+
+/**
+ * Open UNIX domain socket for listining at @a unix_path with
+ * permissions @a unix_mode.
+ *
+ * @param unix_path where to listen
+ * @param unix_mode access permissions to set
+ * @return -1 on error, otherwise the listen socket
+ */
+int
+TALER_MHD2_open_unix_path (const char *unix_path,
+ mode_t unix_mode);
+
+
+/**
+ * Bind a listen socket to the UNIX domain path or the TCP port and IP address
+ * as specified in @a cfg in section @a section. IF only a port was
+ * specified, set @a port and return -1. Otherwise, return the bound file
+ * descriptor.
+ *
+ * @param cfg configuration to parse
+ * @param section configuration section to use
+ * @param[out] port port to set, if TCP without BINDTO
+ * @return -1 and a port of zero on error, otherwise
+ * either -1 and a port, or a bound stream socket
+ */
+int
+TALER_MHD2_bind (const struct GNUNET_CONFIGURATION_Handle *cfg,
+ const char *section,
+ uint16_t *port);
+
+
+/**
+ * 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 loop for MHD.
+ *
+ * @return the daemon that we were previously running,
+ * or NULL if none was active
+ */
+struct MHD_Daemon *
+TALER_MHD2_daemon_stop (void);
+
+
+/**
+ * Trigger MHD daemon that is running. Needed when
+ * a request was resumed.
+ */
+void
+TALER_MHD2_daemon_trigger (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/include/taler_mhd_lib.h b/src/include/taler_mhd_lib.h
@@ -62,6 +62,43 @@ enum TALER_MHD_GlobalOptions
};
+#if MHD_VERSION < 0x00097701
+#define MHD_create_response_from_buffer_static(s, b) \
+ MHD_create_response_from_buffer (s, \
+ (const char *) b, \
+ MHD_RESPMEM_PERSISTENT)
+#endif
+
+
+/**
+ * Find out if an MHD connection is using HTTPS (either
+ * directly or via proxy).
+ *
+ * @param connection MHD connection
+ * @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_mhd_is_https (struct MHD_Connection *connection);
+
+
+/**
+ * Convert query argument to @a yna value.
+ *
+ * @param connection connection 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_MHD_arg_to_yna (struct MHD_Connection *connection,
+ const char *arg,
+ enum TALER_EXCHANGE_YesNoAll default_val,
+ enum TALER_EXCHANGE_YesNoAll *yna);
+
+
/**
* Set global options for response generation within libtalermhd.
*
@@ -134,23 +171,6 @@ TALER_MHD_reply_json_steal (struct MHD_Connection *connection,
/**
* Function to call to handle the request by building a JSON
- * reply from a format string and varargs.
- *
- * @param connection the MHD connection to handle
- * @param response_code HTTP response code to use
- * @param fmt format string for pack
- * @param ... varargs
- * @return MHD result code
- */
-MHD_RESULT
-TALER_MHD_reply_json_pack (struct MHD_Connection *connection,
- unsigned int response_code,
- const char *fmt,
- ...);
-
-
-/**
- * Function to call to handle the request by building a JSON
* reply from varargs.
*
* @param connection the MHD connection to handle
@@ -229,18 +249,6 @@ TALER_MHD_make_json_steal (json_t *json);
/**
* Make JSON response object.
*
- * @param fmt format string for pack
- * @param ... varargs
- * @return MHD response object
- */
-struct MHD_Response *
-TALER_MHD_make_json_pack (const char *fmt,
- ...);
-
-
-/**
- * Make JSON response object.
- *
* @param ... varargs
* @return MHD response object
*/
@@ -517,10 +525,10 @@ TALER_MHD_parse_request_arg_timestamp (struct MHD_Connection *connection,
*/
#define TALER_MHD_parse_request_yna(connection,name,def,ret) \
do { \
- if (! (TALER_arg_to_yna (connection, \
- name, \
- def, \
- ret)) ) \
+ if (! (TALER_MHD_arg_to_yna (connection, \
+ name, \
+ def, \
+ ret)) ) \
{ \
GNUNET_break_op (0); \
return TALER_MHD_reply_with_error ( \
diff --git a/src/include/taler_util.h b/src/include/taler_util.h
@@ -28,16 +28,9 @@
#define __TALER_UTIL_LIB_H_INSIDE__
#include <gnunet/gnunet_util_lib.h>
-#include <microhttpd.h>
#include "taler_amount_lib.h"
#include "taler_crypto_lib.h"
-#if MHD_VERSION < 0x00097701
-#define MHD_create_response_from_buffer_static(s, b) \
- MHD_create_response_from_buffer (s, \
- (const char *) b, \
- MHD_RESPMEM_PERSISTENT)
-#endif
/**
* Version of the Taler API, in hex.
@@ -453,19 +446,6 @@ TALER_pattern_matches (const char *pattern,
/**
- * Find out if an MHD connection is using HTTPS (either
- * directly or via proxy).
- *
- * @param connection MHD connection
- * @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_mhd_is_https (struct MHD_Connection *connection);
-
-
-/**
* Make an absolute URL with query parameters.
*
* If a 'value' is given as NULL, both the key and the value are skipped. Note
@@ -532,21 +512,6 @@ TALER_url_absolute_raw_va (const char *proto,
/**
- * Make an absolute URL for a given MHD connection.
- *
- * @param connection the connection to get the URL for
- * @param path path of the url
- * @param ... NULL-terminated key-value pairs (char *) for query parameters,
- * the value will be url-encoded
- * @returns the URL, must be freed with #GNUNET_free
- */
-char *
-TALER_url_absolute_mhd (struct MHD_Connection *connection,
- const char *path,
- ...);
-
-
-/**
* Obtain the payment method from a @a payto_uri
*
* @param payto_uri the URL to parse
@@ -746,22 +711,6 @@ enum TALER_EXCHANGE_YesNoAll
/**
- * Convert query argument to @a yna value.
- *
- * @param connection connection 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_arg_to_yna (struct MHD_Connection *connection,
- const char *arg,
- enum TALER_EXCHANGE_YesNoAll default_val,
- enum TALER_EXCHANGE_YesNoAll *yna);
-
-
-/**
* Convert YNA value to a string.
*
* @param yna value to convert
diff --git a/src/mhd/Makefile.am b/src/mhd/Makefile.am
@@ -10,6 +10,7 @@ lib_LTLIBRARIES = \
libtalermhd.la
libtalermhd_la_SOURCES = \
+ mhd.c \
mhd_config.c \
mhd_legal.c \
mhd_parsing.c \
@@ -23,6 +24,7 @@ libtalermhd_la_LIBADD = \
$(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/util/libtalerutil.la \
-lgnunetjson \
+ -lgnunetmhd \
-lgnunetutil \
-lmicrohttpd \
-ljansson \
@@ -34,12 +36,9 @@ lib_LTLIBRARIES += \
libtalermhd2.la
libtalermhd2_la_SOURCES = \
- mhd2_config.c \
- mhd2_legal.c \
- mhd2_parsing.c \
+ mhd_config.c \
mhd2_responses.c \
- mhd2_run.c \
- mhd2_spa.c
+ mhd2_run.c
libtalermhd2_la_LDFLAGS = \
-version-info 0:0:0 \
-no-undefined
diff --git a/src/mhd/mhd.c b/src/mhd/mhd.c
@@ -0,0 +1,117 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014-2020 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 mhd.c
+ * @brief MHD utility functions (used by the merchant backend)
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_util.h"
+#include "taler_mhd_lib.h"
+
+/**
+ * Find out if an MHD connection is using HTTPS (either
+ * directly or via proxy).
+ *
+ * @param connection MHD connection
+ * @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_mhd_is_https (struct MHD_Connection *connection)
+{
+ const union MHD_ConnectionInfo *ci;
+ const union MHD_DaemonInfo *di;
+ const char *forwarded_proto = MHD_lookup_connection_value (connection,
+ MHD_HEADER_KIND,
+ "X-Forwarded-Proto");
+
+ if (NULL != forwarded_proto)
+ {
+ if (0 == strcasecmp (forwarded_proto,
+ "https"))
+ return GNUNET_YES;
+ if (0 == strcasecmp (forwarded_proto,
+ "http"))
+ return GNUNET_NO;
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ /* likely not reverse proxy, figure out if we are
+ http by asking MHD */
+ ci = MHD_get_connection_info (connection,
+ MHD_CONNECTION_INFO_DAEMON);
+ if (NULL == ci)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ di = MHD_get_daemon_info (ci->daemon,
+ MHD_DAEMON_INFO_FLAGS);
+ if (NULL == di)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ if (0 != (di->flags & MHD_USE_TLS))
+ return GNUNET_YES;
+ return GNUNET_NO;
+}
+
+
+/**
+ * Convert query argument to @a yna value.
+ *
+ * @param connection connection 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_MHD_arg_to_yna (struct MHD_Connection *connection,
+ const char *arg,
+ enum TALER_EXCHANGE_YesNoAll default_val,
+ enum TALER_EXCHANGE_YesNoAll *yna)
+{
+ const char *str;
+
+ str = MHD_lookup_connection_value (connection,
+ MHD_GET_ARGUMENT_KIND,
+ arg);
+ if (NULL == str)
+ {
+ *yna = default_val;
+ return true;
+ }
+ if (0 == strcasecmp (str, "yes"))
+ {
+ *yna = TALER_EXCHANGE_YNA_YES;
+ return true;
+ }
+ if (0 == strcasecmp (str, "no"))
+ {
+ *yna = TALER_EXCHANGE_YNA_NO;
+ return true;
+ }
+ if (0 == strcasecmp (str, "all"))
+ {
+ *yna = TALER_EXCHANGE_YNA_ALL;
+ return true;
+ }
+ return false;
+}
diff --git a/src/mhd/mhd2_responses.c b/src/mhd/mhd2_responses.c
@@ -0,0 +1,449 @@
+/*
+ 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_util.h"
+#include "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)
+{
+ 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",
+ "*"));
+}
+
+
+bool
+TALER_MHD2_can_compress (struct MHD_Request *request)
+{
+ const struct MHD_StringNullable *aeb;
+ const char *ae;
+ const char *de;
+
+ if (0 != (TM_go & TALER_MHD2_GO_DISABLE_COMPRESSION))
+ return MHD_NO;
+ aeb = MHD_request_get_value (request,
+ MHD_VK_HEADER,
+ MHD_HTTP_HEADER_ACCEPT_ENCODING);
+ ae = aeb->cstr;
+ if (NULL == ae)
+ return false;
+ 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);
+ 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 NULL;
+ }
+ 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 NULL;
+ }
+ TALER_MHD2_add_global_headers (response);
+ 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 NULL;
+ }
+ }
+
+ 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 NULL;
+ /* This adds the Access-Control-Allow-Origin header.
+ * All endpoints of the exchange allow CORS. */
+ TALER_MHD2_add_global_headers (response);
+ 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_NO;
+ }
+ TALER_MHD2_add_global_headers (response);
+ 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 NULL;
+ }
+ 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 NULL;
+ }
+ TALER_MHD2_add_global_headers (response);
+ 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
@@ -0,0 +1,292 @@
+/*
+ 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 "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <jansson.h>
+#define MHD_APP_SOCKET_CNTX_TYPE struct SocketContext
+#include <microhttpd2.h>
+#include "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;
+};
+
+
+/**
+ * Set to true if we should immediately MHD_run() again.
+ */
+static bool triggered;
+
+/**
+ * Task running the HTTP server.
+ */
+static struct GNUNET_SCHEDULER_Task *mhd_task;
+
+/**
+ * The MHD daemon we are running.
+ */
+static struct MHD_Daemon *mhd;
+
+
+/**
+ * Function that queries MHD's select sets and
+ * starts the task waiting for them.
+ */
+static struct GNUNET_SCHEDULER_Task *
+prepare_daemon (void);
+
+
+/**
+ * Trigger MHD on timeout.
+ *
+ * @param cls not used
+ */
+static void
+handle_timeout (void *cls)
+{
+ (void) cls;
+ mhd_task = prepare_daemon ();
+}
+
+
+/**
+ * Function that queries MHD's select sets and
+ * starts the task waiting for them.
+ */
+static struct GNUNET_SCHEDULER_Task *
+prepare_daemon (void)
+{
+ uint_fast64_t next_max_wait;
+
+ GNUNET_break (MHD_SC_OK ==
+ MHD_deamon_process_reg_events (mhd,
+ &next_max_wait));
+ if (MHD_WAIT_INDEFINITELY == next_max_wait)
+ return NULL;
+ return GNUNET_SCHEDULER_add_delayed (
+ GNUNET_TIME_relative_multiply (
+ GNUNET_TIME_UNIT_MICROSECONDS,
+ next_max_wait),
+ &handle_timeout,
+ NULL);
+}
+
+
+/**
+ * Call MHD to process pending requests and then go back
+ * and schedule the next run.
+ *
+ * @param cls NULL
+ */
+static void
+run_daemon (void *cls)
+{
+ (void) cls;
+ mhd_task = NULL;
+ do {
+ triggered = false;
+ GNUNET_break (MHD_SC_OK ==
+ MHD_daemon_process_nonblocking (mhd));
+ } while (triggered);
+ mhd_task = prepare_daemon ();
+}
+
+
+/**
+ * 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;
+
+ sc->mhd_rtask = NULL;
+ MHD_daemon_event_update (mhd,
+ sc->ecb_cntx,
+ MHD_FD_STATE_RECV);
+}
+
+
+/**
+ * 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;
+
+ sc->mhd_wtask = NULL;
+ MHD_daemon_event_update (mhd,
+ sc->ecb_cntx,
+ MHD_FD_STATE_SEND);
+}
+
+
+/**
+ * Callback for registration/de-registration of the sockets to watch.
+ *
+ * @param cls the closure
+ * @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
+ * @ingroup event
+ */
+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)
+{
+ (void) 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);
+ }
+ 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)
+{
+ GNUNET_assert (NULL == mhd);
+ GNUNET_assert (MHD_SC_OK ==
+ MHD_DAEMON_SET_OPTIONS (
+ daemon,
+ MHD_D_OPTION_WM_EXTERNAL_EVENT_LOOP_CB_LEVEL (
+ &socket_registration_update,
+ NULL)));
+ mhd = daemon;
+ mhd_task = prepare_daemon ();
+}
+
+
+struct MHD_Daemon *
+TALER_MHD2_daemon_stop (void)
+{
+ struct MHD_Daemon *ret;
+
+ if (NULL != mhd_task)
+ {
+ GNUNET_SCHEDULER_cancel (mhd_task);
+ mhd_task = NULL;
+ }
+ ret = mhd;
+ mhd = NULL;
+ return ret;
+}
+
+
+void
+TALER_MHD2_daemon_trigger (void)
+{
+ if (NULL != mhd_task)
+ {
+ GNUNET_SCHEDULER_cancel (mhd_task);
+ mhd_task = GNUNET_SCHEDULER_add_now (&run_daemon,
+ NULL);
+ }
+ else
+ {
+ triggered = true;
+ }
+}
+
+
+/* end of mhd2_run.c */
diff --git a/src/mhd/mhd_parsing.c b/src/mhd/mhd_parsing.c
@@ -23,6 +23,7 @@
#include "platform.h"
#include <gnunet/gnunet_util_lib.h>
#include <gnunet/gnunet_json_lib.h>
+#include <gnunet/gnunet_mhd_lib.h>
#include "taler_json_lib.h"
#include "taler_mhd_lib.h"
@@ -34,17 +35,17 @@ TALER_MHD_parse_post_json (struct MHD_Connection *connection,
size_t *upload_data_size,
json_t **json)
{
- enum GNUNET_JSON_PostResult pr;
-
- pr = GNUNET_JSON_post_parser (TALER_MHD_REQUEST_BUFFER_MAX,
- connection,
- con_cls,
- upload_data,
- upload_data_size,
- json);
+ enum GNUNET_MHD_PostResult pr;
+
+ pr = GNUNET_MHD_post_parser (TALER_MHD_REQUEST_BUFFER_MAX,
+ connection,
+ con_cls,
+ upload_data,
+ upload_data_size,
+ json);
switch (pr)
{
- case GNUNET_JSON_PR_OUT_OF_MEMORY:
+ case GNUNET_MHD_PR_OUT_OF_MEMORY:
GNUNET_break (NULL == *json);
return (MHD_NO ==
TALER_MHD_reply_with_error (
@@ -53,15 +54,15 @@ TALER_MHD_parse_post_json (struct MHD_Connection *connection,
TALER_EC_GENERIC_PARSER_OUT_OF_MEMORY,
NULL)) ? GNUNET_SYSERR : GNUNET_NO;
- case GNUNET_JSON_PR_CONTINUE:
+ case GNUNET_MHD_PR_CONTINUE:
GNUNET_break (NULL == *json);
return GNUNET_YES;
- case GNUNET_JSON_PR_REQUEST_TOO_LARGE:
+ case GNUNET_MHD_PR_REQUEST_TOO_LARGE:
GNUNET_break (NULL == *json);
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Closing connection, upload too large\n");
return GNUNET_SYSERR;
- case GNUNET_JSON_PR_JSON_INVALID:
+ case GNUNET_MHD_PR_JSON_INVALID:
GNUNET_break (NULL == *json);
return (MHD_YES ==
TALER_MHD_reply_with_error (connection,
@@ -69,7 +70,7 @@ TALER_MHD_parse_post_json (struct MHD_Connection *connection,
TALER_EC_GENERIC_JSON_INVALID,
NULL))
? GNUNET_NO : GNUNET_SYSERR;
- case GNUNET_JSON_PR_SUCCESS:
+ case GNUNET_MHD_PR_SUCCESS:
GNUNET_break (NULL != *json);
return GNUNET_YES;
}
@@ -82,7 +83,7 @@ TALER_MHD_parse_post_json (struct MHD_Connection *connection,
void
TALER_MHD_parse_post_cleanup_callback (void *con_cls)
{
- GNUNET_JSON_post_parser_cleanup (con_cls);
+ GNUNET_MHD_post_parser_cleanup (con_cls);
}
diff --git a/src/mhd/mhd_responses.c b/src/mhd/mhd_responses.c
@@ -285,87 +285,6 @@ TALER_MHD_reply_cors_preflight (struct MHD_Connection *connection)
}
-MHD_RESULT
-TALER_MHD_reply_json_pack (struct MHD_Connection *connection,
- unsigned int response_code,
- const char *fmt,
- ...)
-{
- json_t *json;
- json_error_t jerror;
-
- {
- va_list argp;
-
- va_start (argp,
- fmt);
- json = json_vpack_ex (&jerror,
- 0,
- fmt,
- argp);
- va_end (argp);
- }
-
- if (NULL == json)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to pack JSON with format `%s': %s\n",
- fmt,
- jerror.text);
- GNUNET_break (0);
- return MHD_NO;
- }
-
- {
- MHD_RESULT ret;
-
- ret = TALER_MHD_reply_json (connection,
- json,
- response_code);
- json_decref (json);
- return ret;
- }
-}
-
-
-struct MHD_Response *
-TALER_MHD_make_json_pack (const char *fmt,
- ...)
-{
- json_t *json;
- json_error_t jerror;
-
- {
- va_list argp;
-
- va_start (argp, fmt);
- json = json_vpack_ex (&jerror,
- 0,
- fmt,
- argp);
- va_end (argp);
- }
-
- if (NULL == json)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to pack JSON with format `%s': %s\n",
- fmt,
- jerror.text);
- GNUNET_break (0);
- return NULL;
- }
-
- {
- struct MHD_Response *response;
-
- response = TALER_MHD_make_json (json);
- json_decref (json);
- return response;
- }
-}
-
-
struct MHD_Response *
TALER_MHD_make_error (enum TALER_ErrorCode ec,
const char *detail)
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
@@ -99,7 +99,6 @@ libtalerutil_la_SOURCES = \
iban.c \
kyc_signatures.c \
merchant_signatures.c \
- mhd.c \
offline_signatures.c \
payto.c \
secmod_common.c secmod_common.h \
diff --git a/src/util/mhd.c b/src/util/mhd.c
@@ -1,135 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 2014-2020 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 mhd.c
- * @brief MHD utility functions (used by the merchant backend)
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include "taler_util.h"
-
-
-/**
- * Find out if an MHD connection is using HTTPS (either
- * directly or via proxy).
- *
- * @param connection MHD connection
- * @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_mhd_is_https (struct MHD_Connection *connection)
-{
- const union MHD_ConnectionInfo *ci;
- const union MHD_DaemonInfo *di;
- const char *forwarded_proto = MHD_lookup_connection_value (connection,
- MHD_HEADER_KIND,
- "X-Forwarded-Proto");
-
- if (NULL != forwarded_proto)
- {
- if (0 == strcasecmp (forwarded_proto,
- "https"))
- return GNUNET_YES;
- if (0 == strcasecmp (forwarded_proto,
- "http"))
- return GNUNET_NO;
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- /* likely not reverse proxy, figure out if we are
- http by asking MHD */
- ci = MHD_get_connection_info (connection,
- MHD_CONNECTION_INFO_DAEMON);
- if (NULL == ci)
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- di = MHD_get_daemon_info (ci->daemon,
- MHD_DAEMON_INFO_FLAGS);
- if (NULL == di)
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- if (0 != (di->flags & MHD_USE_TLS))
- return GNUNET_YES;
- return GNUNET_NO;
-}
-
-
-/**
- * Make an absolute URL for a given MHD connection.
- *
- * @param connection the connection to get the URL for
- * @param path path of the url
- * @param ... NULL-terminated key-value pairs (char *) for query parameters,
- * the value will be url-encoded
- * @returns the URL, must be freed with #GNUNET_free
- */
-char *
-TALER_url_absolute_mhd (struct MHD_Connection *connection,
- const char *path,
- ...)
-{
- /* By default we assume we're running under HTTPS */
- const char *proto;
- const char *host;
- const char *forwarded_host;
- const char *prefix;
- va_list args;
- char *result;
-
- if (GNUNET_YES == TALER_mhd_is_https (connection))
- proto = "https";
- else
- proto = "http";
-
- host = MHD_lookup_connection_value (connection,
- MHD_HEADER_KIND,
- "Host");
- forwarded_host = MHD_lookup_connection_value (connection,
- MHD_HEADER_KIND,
- "X-Forwarded-Host");
-
- prefix = MHD_lookup_connection_value (connection,
- MHD_HEADER_KIND,
- "X-Forwarded-Prefix");
- if (NULL == prefix)
- prefix = "";
-
- if (NULL != forwarded_host)
- host = forwarded_host;
-
- if (NULL == host)
- {
- /* Should never happen, at last the host header should be defined */
- GNUNET_break (0);
- return NULL;
- }
-
- va_start (args,
- path);
- result = TALER_url_absolute_raw_va (proto,
- host,
- prefix,
- path,
- args);
- va_end (args);
- return result;
-}
diff --git a/src/util/yna.c b/src/util/yna.c
@@ -23,50 +23,6 @@
/**
- * Convert query argument to @a yna value.
- *
- * @param connection connection 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_arg_to_yna (struct MHD_Connection *connection,
- const char *arg,
- enum TALER_EXCHANGE_YesNoAll default_val,
- enum TALER_EXCHANGE_YesNoAll *yna)
-{
- const char *str;
-
- str = MHD_lookup_connection_value (connection,
- MHD_GET_ARGUMENT_KIND,
- arg);
- if (NULL == str)
- {
- *yna = default_val;
- return true;
- }
- if (0 == strcasecmp (str, "yes"))
- {
- *yna = TALER_EXCHANGE_YNA_YES;
- return true;
- }
- if (0 == strcasecmp (str, "no"))
- {
- *yna = TALER_EXCHANGE_YNA_NO;
- return true;
- }
- if (0 == strcasecmp (str, "all"))
- {
- *yna = TALER_EXCHANGE_YNA_ALL;
- return true;
- }
- return false;
-}
-
-
-/**
* Convert YNA value to a string.
*
* @param yna value to convert