summaryrefslogtreecommitdiff
path: root/src/backend/taler-merchant-httpd_templating.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2022-08-16 14:06:46 +0200
committerChristian Grothoff <christian@grothoff.org>2022-08-16 14:06:46 +0200
commitc1d0a7d2e64fd7c6bd041a5259cf212b3aabd414 (patch)
tree8b5c4d05187336048f13c1e500501f6e6bbda727 /src/backend/taler-merchant-httpd_templating.c
parent19010a2f6d658e78ded8abb02995d9154d22bbf3 (diff)
downloadmerchant-c1d0a7d2e64fd7c6bd041a5259cf212b3aabd414.tar.gz
merchant-c1d0a7d2e64fd7c6bd041a5259cf212b3aabd414.tar.bz2
merchant-c1d0a7d2e64fd7c6bd041a5259cf212b3aabd414.zip
-move templating logic to libtalertemplating of exchange
Diffstat (limited to 'src/backend/taler-merchant-httpd_templating.c')
-rw-r--r--src/backend/taler-merchant-httpd_templating.c452
1 files changed, 0 insertions, 452 deletions
diff --git a/src/backend/taler-merchant-httpd_templating.c b/src/backend/taler-merchant-httpd_templating.c
deleted file mode 100644
index 9d7766b9..00000000
--- a/src/backend/taler-merchant-httpd_templating.c
+++ /dev/null
@@ -1,452 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 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 taler-merchant-httpd_templating.c
- * @brief logic to load and complete HTML templates
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <taler/taler_util.h>
-#include <taler/taler_mhd_lib.h>
-#include "taler-merchant-httpd_templating.h"
-#include "../mustach/mustach.h"
-#include "../mustach/mustach-jansson.h"
-#include <gnunet/gnunet_mhd_compat.h>
-
-
-/**
- * Entry in a key-value array we use to cache templates.
- */
-struct TVE
-{
- /**
- * A name, used as the key. NULL for the last entry.
- */
- char *name;
-
- /**
- * Language the template is in.
- */
- char *lang;
-
- /**
- * 0-terminated (!) file data to return for @e name and @e lang.
- */
- char *value;
-
-};
-
-
-/**
- * Array of templates loaded into RAM.
- */
-static struct TVE *loaded;
-
-/**
- * Length of the #loaded array.
- */
-static unsigned int loaded_length;
-
-
-/**
- * Load Mustach template into memory. Note that we intentionally cache
- * failures, that is if we ever failed to load a template, we will never try
- * again.
- *
- * @param connection the connection we act upon
- * @param name name of the template file to load
- * (MUST be a 'static' string in memory!)
- * @return NULL on error, otherwise the template
- */
-static const char *
-lookup_template (struct MHD_Connection *connection,
- const char *name)
-{
- struct TVE *best = NULL;
- const char *lang;
-
- lang = MHD_lookup_connection_value (connection,
- MHD_HEADER_KIND,
- MHD_HTTP_HEADER_ACCEPT_LANGUAGE);
- if (NULL == lang)
- lang = "en";
- /* find best match by language */
- for (unsigned int i = 0; i<loaded_length; i++)
- {
- if (0 != strcmp (loaded[i].name,
- name))
- continue; /* does not match by name */
- if ( (NULL == best) ||
- (TALER_language_matches (lang,
- loaded[i].lang) >
- TALER_language_matches (lang,
- best->lang) ) )
- best = &loaded[i];
- }
- if (NULL == best)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "No templates found in `%s'\n",
- name);
- return NULL;
- }
- return best->value;
-}
-
-/**
- * Get the base URL for static resources.
- *
- * @param con the MHD connection
- * @param instance_id the instance ID
- * @returns the static files base URL, guaranteed
- * to have a trailing slash.
- */
-static char *
-make_static_url (struct MHD_Connection *con,
- const char *instance_id)
-{
- const char *host;
- const char *forwarded_host;
- const char *uri_path;
- struct GNUNET_Buffer buf = { 0 };
-
- host = MHD_lookup_connection_value (con,
- MHD_HEADER_KIND,
- "Host");
- forwarded_host = MHD_lookup_connection_value (con,
- MHD_HEADER_KIND,
- "X-Forwarded-Host");
-
- uri_path = MHD_lookup_connection_value (con,
- MHD_HEADER_KIND,
- "X-Forwarded-Prefix");
- if (NULL != forwarded_host)
- host = forwarded_host;
-
- if (NULL == host)
- {
- GNUNET_break (0);
- return NULL;
- }
-
- GNUNET_assert (NULL != instance_id);
-
- if (GNUNET_NO == TALER_mhd_is_https (con))
- GNUNET_buffer_write_str (&buf,
- "http://");
- else
- GNUNET_buffer_write_str (&buf,
- "https://");
- GNUNET_buffer_write_str (&buf,
- host);
- if (NULL != uri_path)
- GNUNET_buffer_write_path (&buf,
- uri_path);
- if (0 != strcmp ("default",
- instance_id))
- {
- GNUNET_buffer_write_path (&buf,
- "instances");
- GNUNET_buffer_write_path (&buf,
- instance_id);
- }
- GNUNET_buffer_write_path (&buf,
- "static/");
- return GNUNET_buffer_reap_str (&buf);
-}
-
-
-
-
-/**
- * Load a @a template and substitute using @a root, returning
- * the result to the @a connection with the given
- * @a http_status code.
- *
- * @param connection the connection we act upon
- * @param http_status code to use on success
- * @param template basename of the template to load
- * @param instance_id instance ID, used to compute static files URL
- * @param taler_uri value for "Taler:" header to set, or NULL
- * @param root JSON object to pass as the root context
- * @return #GNUNET_OK on success (reply queued), #GNUNET_NO if an error was queued,
- * #GNUNET_SYSERR on failure (to queue an error)
- */
-enum GNUNET_GenericReturnValue
-TMH_return_from_template (struct MHD_Connection *connection,
- unsigned int http_status,
- const char *template,
- const char *instance_id,
- const char *taler_uri,
- json_t *root)
-{
- struct MHD_Response *reply;
- char *body;
- size_t body_size;
-
- {
- const char *tmpl;
- int eno;
-
- tmpl = lookup_template (connection,
- template);
- if (NULL == tmpl)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to load template `%s'\n",
- template);
- if (MHD_YES !=
- TALER_MHD_reply_with_error (connection,
- MHD_HTTP_NOT_ACCEPTABLE,
- TALER_EC_MERCHANT_GENERIC_FAILED_TO_LOAD_TEMPLATE,
- template))
- return GNUNET_SYSERR;
- return GNUNET_NO;
- }
- /* Add default values to the context */
- {
- char *static_url = make_static_url (connection,
- instance_id);
- json_object_set (root,
- "static_url",
- json_string (static_url));
- GNUNET_free (static_url);
- }
- if (0 !=
- (eno = mustach_jansson (tmpl,
- root,
- &body,
- &body_size)))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "mustach failed on template `%s' with error %d\n",
- template,
- eno);
- if (MHD_YES !=
- TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_MERCHANT_GENERIC_FAILED_TO_EXPAND_TEMPLATE,
- template))
- return GNUNET_SYSERR;
- return GNUNET_NO;
- }
- }
-
- /* try to compress reply if client allows it */
- {
- bool compressed = false;
-
- if (MHD_YES ==
- TALER_MHD_can_compress (connection))
- {
- compressed = TALER_MHD_body_compress ((void **) &body,
- &body_size);
- }
- reply = MHD_create_response_from_buffer (body_size,
- body,
- MHD_RESPMEM_MUST_FREE);
- if (NULL == reply)
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- if (compressed)
- {
- if (MHD_NO ==
- MHD_add_response_header (reply,
- MHD_HTTP_HEADER_CONTENT_ENCODING,
- "deflate"))
- {
- GNUNET_break (0);
- MHD_destroy_response (reply);
- return GNUNET_SYSERR;
- }
- }
- }
-
- /* Add standard headers */
- if (NULL != taler_uri)
- GNUNET_break (MHD_NO !=
- MHD_add_response_header (reply,
- "Taler",
- taler_uri));
- GNUNET_break (MHD_NO !=
- MHD_add_response_header (reply,
- MHD_HTTP_HEADER_CONTENT_TYPE,
- "text/html"));
-
- /* Actually return reply */
- {
- MHD_RESULT ret;
-
- ret = MHD_queue_response (connection,
- http_status,
- reply);
- MHD_destroy_response (reply);
- if (MHD_NO == ret)
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Function called with a template's filename.
- *
- * @param cls closure
- * @param filename complete filename (absolute path)
- * @return #GNUNET_OK to continue to iterate,
- * #GNUNET_NO to stop iteration with no error,
- * #GNUNET_SYSERR to abort iteration with error!
- */
-static int
-load_template (void *cls,
- const char *filename)
-{
- char *lang;
- char *end;
- int fd;
- struct stat sb;
- char *map;
- const char *name;
-
- if ('.' == filename[0])
- return GNUNET_OK;
-
- name = strrchr (filename,
- '/');
- if (NULL == name)
- name = filename;
- else
- name++;
- lang = strchr (name,
- '.');
- if (NULL == lang)
- return GNUNET_OK; /* name must include .$LANG */
- lang++;
- end = strchr (lang,
- '.');
- if ( (NULL == end) ||
- (0 != strcmp (end,
- ".must")) )
- return GNUNET_OK; /* name must end with '.must' */
-
- /* finally open template */
- fd = open (filename,
- O_RDONLY);
- if (-1 == fd)
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
- "open",
- filename);
-
- return GNUNET_SYSERR;
- }
- if (0 !=
- fstat (fd,
- &sb))
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
- "open",
- filename);
- GNUNET_break (0 == close (fd));
- return GNUNET_OK;
- }
- map = GNUNET_malloc_large (sb.st_size + 1);
- if (NULL == map)
- {
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
- "malloc");
- GNUNET_break (0 == close (fd));
- return GNUNET_SYSERR;
- }
- if (sb.st_size !=
- read (fd,
- map,
- sb.st_size))
- {
- GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
- "read",
- filename);
- GNUNET_break (0 == close (fd));
- return GNUNET_OK;
- }
- GNUNET_break (0 == close (fd));
- GNUNET_array_grow (loaded,
- loaded_length,
- loaded_length + 1);
- loaded[loaded_length - 1].name = GNUNET_strndup (name,
- (lang - 1) - name);
- loaded[loaded_length - 1].lang = GNUNET_strndup (lang,
- end - lang);
- loaded[loaded_length - 1].value = map;
- return GNUNET_OK;
-}
-
-
-/**
- * Preload templates.
- */
-int
-TMH_templating_init ()
-{
- char *dn;
- int ret;
-
- {
- char *path;
-
- path = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
- if (NULL == path)
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- GNUNET_asprintf (&dn,
- "%s/merchant/templates/",
- path);
- GNUNET_free (path);
- }
- ret = GNUNET_DISK_directory_scan (dn,
- &load_template,
- NULL);
- GNUNET_free (dn);
- if (-1 == ret)
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Nicely shut down.
- */
-void __attribute__ ((destructor))
-templating_fini ()
-{
- for (unsigned int i = 0; i<loaded_length; i++)
- {
- GNUNET_free (loaded[i].name);
- GNUNET_free (loaded[i].lang);
- GNUNET_free (loaded[i].value);
- }
- GNUNET_array_grow (loaded,
- loaded_length,
- 0);
-}