commit 241a5e964502180add6c2e5bbb18eb4e61bb4238
parent 6c993afa87f882acf31de13af4f551b5f8171f0e
Author: Christian Grothoff <christian@grothoff.org>
Date: Mon, 20 Apr 2026 18:50:29 +0200
start to implement template logic
Diffstat:
6 files changed, 283 insertions(+), 43 deletions(-)
diff --git a/src/backend/paivana-httpd.c b/src/backend/paivana-httpd.c
@@ -54,14 +54,15 @@ int PH_no_check;
int PH_global_ret;
/**
- * Closure for #GNUNET_CURL_gnunet_scheduler_reschedule().
+ * Our configuration.
*/
-static struct GNUNET_CURL_RescheduleContext *ctx_rc;
+const struct GNUNET_CONFIGURATION_Handle *PH_cfg;
+
/**
- * Our configuration.
+ * Closure for #GNUNET_CURL_gnunet_scheduler_reschedule().
*/
-static const struct GNUNET_CONFIGURATION_Handle *cfg;
+static struct GNUNET_CURL_RescheduleContext *ctx_rc;
/* *************** General / main code *************** */
@@ -121,7 +122,7 @@ run (void *cls,
(void) cls;
(void) args;
(void) cfgfile;
- cfg = c;
+ PH_cfg = c;
if (! PAIVANA_HTTPD_reverse_init ())
{
@@ -254,8 +255,9 @@ run (void *cls,
GNUNET_free (auth_header);
}
ctx_rc = GNUNET_CURL_gnunet_rc_create (PH_ctx);
- PAIVANA_HTTPD_load_templates (&PAIVANA_HTTPD_serve_requests,
- (void *) c);
+ /* Once templates are done loading, this will
+ start the daemon as well */
+ PAIVANA_HTTPD_load_templates ();
}
diff --git a/src/backend/paivana-httpd.h b/src/backend/paivana-httpd.h
@@ -69,4 +69,10 @@ extern int PH_no_check;
*/
extern int PH_global_ret;
+/**
+ * Our configuration.
+ */
+extern const struct GNUNET_CONFIGURATION_Handle *PH_cfg;
+
+
#endif
diff --git a/src/backend/paivana-httpd_daemon.c b/src/backend/paivana-httpd_daemon.c
@@ -313,12 +313,11 @@ start_daemon (void *cls,
void
-PAIVANA_HTTPD_serve_requests (void *cls)
+PAIVANA_HTTPD_serve_requests ()
{
- const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
enum GNUNET_GenericReturnValue ret;
- ret = TALER_MHD_listen_bind (cfg,
+ ret = TALER_MHD_listen_bind (PH_cfg,
"paivana",
&start_daemon,
NULL);
diff --git a/src/backend/paivana-httpd_daemon.h b/src/backend/paivana-httpd_daemon.h
@@ -33,11 +33,9 @@
/**
* Start the HTTP server and begin serving requests.
- *
- * @param cls pass the `const struct GNUNET_CONFIGURATION_Handle`
*/
void
-PAIVANA_HTTPD_serve_requests (void *cls);
+PAIVANA_HTTPD_serve_requests (void);
#endif
diff --git a/src/backend/paivana-httpd_templates.c b/src/backend/paivana-httpd_templates.c
@@ -28,29 +28,97 @@
#include <gnunet/gnunet_util_lib.h>
#include <gnunet/gnunet_curl_lib.h>
#include "paivana-httpd.h"
+#include "paivana-httpd_daemon.h"
#include "paivana-httpd_templates.h"
#include <taler/taler_mhd_lib.h>
#include "paivana_pd.h"
+#include <regex.h>
-// FIXME: make part of our template structure...
+struct Template;
+#define TALER_MERCHANT_GET_PRIVATE_TEMPLATE_RESULT_CLOSURE struct Template
+#include <taler/merchant/get-private-templates-TEMPLATE_ID.h>
+#include <taler/merchant/get-private-templates.h>
+
+/**
+ * Information about a template in the merchant backend.
+ */
+struct Template
+{
+
+ /**
+ * Kept in a DLL.
+ */
+ struct Template *next;
+
+ /**
+ * Kept in a DLL.
+ */
+ struct Template *prev;
+
+ /**
+ * ID of the template.
+ */
+ char *template_id;
+
+ /**
+ * Regular expression of websites the template is for.
+ */
+ char *regex;
+
+ /**
+ * Pre-compiled regular expression @e regex.
+ */
+ regex_t ex;
+
+ /**
+ * Handle used to request more information about the template.
+ */
+ struct TALER_MERCHANT_GetPrivateTemplateHandle *gt;
+
+ /**
+ * Paywall response for this template. NULL for no paywall.
+ */
+ struct MHD_Response *paywall;
+
+};
+
+
+/**
+ * Kept in a DLL.
+ */
+static struct Template *t_head;
+
/**
- * Static paywall response.
+ * Kept in a DLL.
*/
-static struct MHD_Response *paywall;
+static struct Template *t_tail;
+
+
+/**
+ * Handle to get all the templates.
+ */
+static struct TALER_MERCHANT_GetPrivateTemplatesHandle *gpt;
/**
* Try to initialize the paywall response.
+ *
+ * @param template_id template to use for the response
+ * @return HTTP response to return for matching websites
*/
-static bool
-load_paywall (void)
+static struct MHD_Response *
+load_paywall (const char *template_id)
{
+ struct MHD_Response *paywall;
char *tpath;
char *fn;
int fd;
struct stat sb;
+ // FIXME: use templating logic to modify HTML
+ // based on template_id, backend base URL and
+ // possibly other values!
tpath = GNUNET_OS_installation_get_path (PAIVANA_project_data (),
GNUNET_OS_IPK_DATADIR);
GNUNET_asprintf (&fn,
@@ -76,43 +144,190 @@ load_paywall (void)
fn);
GNUNET_free (fn);
GNUNET_break (0 == close (fd));
- return false;
+ return NULL;
}
GNUNET_free (fn);
paywall = MHD_create_response_from_fd (sb.st_size,
fd);
if (NULL == paywall)
- return false;
+ return NULL;
GNUNET_break (MHD_YES ==
MHD_add_response_header (paywall,
MHD_HTTP_HEADER_CONTENT_TYPE,
"text/html"));
- return true;
+ return paywall;
+}
+
+
+/**
+ * Parse template contract to (mostly) determine the
+ * regex specifying which websites the template applies to.
+ *
+ * @param[in,out] t template to update
+ * @param contract contract to parse
+ */
+static void
+parse_template (struct Template *t,
+ const json_t *contract)
+{
+ const char *regex = NULL;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_string ("website_regex",
+ ®ex),
+ NULL),
+ GNUNET_JSON_spec_end ()
+ };
+ const char *en;
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse ((json_t *) contract,
+ spec,
+ &en,
+ NULL))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Invalid template %s at field %s\n",
+ t->template_id,
+ en);
+ return;
+ }
+ if (0 != regcomp (&t->ex,
+ regex,
+ REG_NOSUB | REG_EXTENDED))
+ {
+ GNUNET_break_op (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Invalid regex in template %s: %s\n",
+ t->template_id,
+ regex);
+ return;
+ }
+ t->regex = GNUNET_strdup (regex);
+}
+
+
+/**
+ * Callback for a GET /private/templates/$TEMPLATE_ID request.
+ *
+ * @param cls closure
+ * @param tgr response details
+ */
+static void
+setup_template (
+ struct Template *t,
+ const struct TALER_MERCHANT_GetPrivateTemplateResponse *tgr)
+{
+ t->gt = NULL;
+ switch (tgr->hr.http_status)
+ {
+ case MHD_HTTP_OK:
+ parse_template (t,
+ tgr->details.ok.template_contract);
+ break;
+ default:
+ GNUNET_break (0);
+ break;
+ }
+ if (t->regex)
+ {
+ t->paywall = load_paywall (t->template_id);
+ }
+ for (struct Template *p = t_head; NULL != p; p = p->next)
+ if (NULL != p->gt)
+ return;
+ /* all templates done, continue with main logic */
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Templates loaded, starting to serve requests\n");
+ PAIVANA_HTTPD_serve_requests ();
+}
+
+
+/**
+ * Callback for a GET /private/templates request.
+ *
+ * @param cls closure
+ * @param tgr response details
+ */
+static void
+check_templates (
+ void *cls,
+ const struct TALER_MERCHANT_GetPrivateTemplatesResponse *tgr)
+{
+ gpt = NULL;
+ switch (tgr->hr.http_status)
+ {
+ case MHD_HTTP_OK:
+ break;
+ case MHD_HTTP_NO_CONTENT:
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "No templates found, starting to serve requests\n");
+ PAIVANA_HTTPD_serve_requests ();
+ return;
+ default:
+ GNUNET_break (0);
+ PH_global_ret = EXIT_FAILURE;
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ if (0 == tgr->details.ok.templates_length)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "No templates found, starting to serve requests\n");
+ PAIVANA_HTTPD_serve_requests ();
+ return;
+ }
+
+ for (unsigned int i = 0; i<tgr->details.ok.templates_length; i++)
+ {
+ const struct TALER_MERCHANT_GetPrivateTemplatesTemplateEntry *te
+ = &tgr->details.ok.templates[i];
+ struct Template *t;
+
+ t = GNUNET_new (struct Template);
+ t->template_id = GNUNET_strdup (te->template_id);
+ t->gt = TALER_MERCHANT_get_private_template_create (PH_ctx,
+ PH_merchant_base_url,
+ t->template_id);
+ GNUNET_CONTAINER_DLL_insert (t_head,
+ t_tail,
+ t);
+ GNUNET_assert (
+ TALER_EC_NONE ==
+ TALER_MERCHANT_get_private_template_start (t->gt,
+ &setup_template,
+ t));
+ }
}
void
-PAIVANA_HTTPD_load_templates (GNUNET_SCHEDULER_TaskCallback cb,
- void *cb_cls)
+PAIVANA_HTTPD_load_templates ()
{
- // FIXME: not implemented!
- GNUNET_SCHEDULER_add_now (cb,
- cb_cls);
- // -> Note: needs *restart* on template changes!
- // -> in future: long-poll on GET /private/templates?
+ gpt = TALER_MERCHANT_get_private_templates_create (PH_ctx,
+ PH_merchant_base_url);
+ GNUNET_assert (NULL != gpt);
+ GNUNET_assert (
+ TALER_EC_NONE ==
+ TALER_MERCHANT_get_private_templates_start (gpt,
+ &check_templates,
+ NULL));
}
struct MHD_Response *
PAIVANA_HTTPD_search_templates (const char *website)
{
- // FIXME: check if url is one that we require payment for,
- // if not return NULL
- // (also should determine WHICH payment template
- // we use => load *all* templates of the instance,
- // pre-compile *all* regexes and then match!)
-
- // FIXME: not implemented
+ for (struct Template *t = t_head; NULL != t; t = t->next)
+ {
+ if (NULL == t->regex)
+ continue;
+ if (0 == regexec (&t->ex,
+ website,
+ 0, NULL,
+ 0))
+ return t->paywall;
+ }
return NULL;
}
@@ -123,4 +338,28 @@ PAIVANA_HTTPD_search_templates (const char *website)
void
PAIVANA_HTTPD_unload_templates ()
{
+ while (NULL != t_head)
+ {
+ struct Template *t = t_head;
+
+ GNUNET_CONTAINER_DLL_remove (t_head,
+ t_tail,
+ t);
+ if (NULL != t->gt)
+ TALER_MERCHANT_get_private_template_cancel (t->gt);
+ if (NULL != t->paywall)
+ MHD_destroy_response (t->paywall);
+ if (NULL != t->regex)
+ {
+ regfree (&t->ex);
+ GNUNET_free (t->regex);
+ }
+ GNUNET_free (t->template_id);
+ GNUNET_free (t);
+ }
+ if (NULL != gpt)
+ {
+ TALER_MERCHANT_get_private_templates_cancel (gpt);
+ gpt = NULL;
+ }
}
diff --git a/src/backend/paivana-httpd_templates.h b/src/backend/paivana-httpd_templates.h
@@ -31,16 +31,12 @@
/**
- * Load the templates from the merchant backend.
- * Calls @a cb upon completion if successful, otherwise
- * may initiate shutdown.
- *
- * @param cb continuation to call when done
- * @param cb_cls closure for @a cb
+ * Load the templates from the merchant backend. Calls
+ * PAIVANA_HTTPD_serve_requests() upon completion if successful,
+ * otherwise may initiate shutdown.
*/
void
-PAIVANA_HTTPD_load_templates (GNUNET_SCHEDULER_TaskCallback cb,
- void *cb_cls);
+PAIVANA_HTTPD_load_templates (void);
/**