gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-exchange] branch master updated: tos


From: gnunet
Subject: [taler-exchange] branch master updated: tos
Date: Mon, 02 Dec 2019 21:26:22 +0100

This is an automated email from the git hooks/post-receive script.

grothoff pushed a commit to branch master
in repository exchange.

The following commit(s) were added to refs/heads/master by this push:
     new 1043bc83 tos
1043bc83 is described below

commit 1043bc839f6bbdf23eb0aa0c4a84165b91828753
Author: Christian Grothoff <address@hidden>
AuthorDate: Mon Dec 2 21:26:19 2019 +0100

    tos
---
 src/exchange/Makefile.am                  |   1 +
 src/exchange/taler-exchange-httpd.c       |   2 +
 src/exchange/taler-exchange-httpd_terms.c | 507 ++++++++++++++++++++++++++++++
 src/exchange/taler-exchange-httpd_terms.h |  49 +++
 4 files changed, 559 insertions(+)

diff --git a/src/exchange/Makefile.am b/src/exchange/Makefile.am
index 8e162182..fa359411 100644
--- a/src/exchange/Makefile.am
+++ b/src/exchange/Makefile.am
@@ -55,6 +55,7 @@ taler_exchange_httpd_SOURCES = \
   taler-exchange-httpd_reserve_status.c taler-exchange-httpd_reserve_status.h \
   taler-exchange-httpd_reserve_withdraw.c 
taler-exchange-httpd_reserve_withdraw.h \
   taler-exchange-httpd_responses.c taler-exchange-httpd_responses.h \
+  taler-exchange-httpd_terms.c taler-exchange-httpd_terms.h \
   taler-exchange-httpd_track_transaction.c 
taler-exchange-httpd_track_transaction.h \
   taler-exchange-httpd_track_transfer.c taler-exchange-httpd_track_transfer.h \
   taler-exchange-httpd_wire.c taler-exchange-httpd_wire.h \
diff --git a/src/exchange/taler-exchange-httpd.c 
b/src/exchange/taler-exchange-httpd.c
index bcac62ce..e53555d6 100644
--- a/src/exchange/taler-exchange-httpd.c
+++ b/src/exchange/taler-exchange-httpd.c
@@ -36,6 +36,7 @@
 #include "taler-exchange-httpd_refresh_link.h"
 #include "taler-exchange-httpd_refresh_melt.h"
 #include "taler-exchange-httpd_refresh_reveal.h"
+#include "taler-exchange-httpd_terms.h"
 #include "taler-exchange-httpd_track_transfer.h"
 #include "taler-exchange-httpd_track_transaction.h"
 #include "taler-exchange-httpd_keystate.h"
@@ -883,6 +884,7 @@ main (int argc,
   if (GNUNET_OK !=
       exchange_serve_process_config ())
     return 1;
+  TEH_load_terms (cfg);
 
   /* check for systemd-style FD passing */
   listen_pid = getenv ("LISTEN_PID");
diff --git a/src/exchange/taler-exchange-httpd_terms.c 
b/src/exchange/taler-exchange-httpd_terms.c
new file mode 100644
index 00000000..dadc1588
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_terms.c
@@ -0,0 +1,507 @@
+/*
+  This file is part of TALER
+  Copyright (C) 2019 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-exchange-httpd_terms.c
+ * @brief Handle /terms requests to return the terms of service
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_json_lib.h>
+#include <jansson.h>
+#include <microhttpd.h>
+#include "taler_mhd_lib.h"
+#include "taler-exchange-httpd_responses.h"
+
+
+/**
+ * Entry in the terms-of-service array.
+ */
+struct Terms
+{
+  /**
+   * Mime type of the terms.
+   */
+  const char *mime_type;
+
+  /**
+   * The terms (NOT 0-terminated!).
+   */
+  const void *terms;
+
+  /**
+   * The desired language.
+   */
+  const char *language;
+
+  /**
+   * Number of bytes in @e terms.
+   */
+  size_t terms_size;
+};
+
+
+/**
+ * Array of terms of service, terminated by NULL/0 value.
+ */
+static struct Terms *terms;
+
+/**
+ * Length of the #terms array.
+ */
+static unsigned int terms_len;
+
+/**
+ * Etag to use for the terms of service (= version).
+ */
+static char *terms_etag;
+
+
+/**
+ * Check if @a mime matches the @a accept_pattern.
+ *
+ * @param accept_pattern a mime pattern like text/plain or image/<STAR>
+ * @param mime the mime type to match
+ * @return true if @a mime matches the @a accept_pattern
+ */
+static bool
+mime_matches (const char *accept_pattern,
+              const char *mime)
+{
+  const char *da = strchr (accept_pattern, '/');
+  const char *dm = strchr (mime, '/');
+
+  if ( (NULL == da) ||
+       (NULL == dm) )
+    return (0 == strcmp ("*", accept_pattern));
+  return
+    ( ( (1 == da - accept_pattern) &&
+        ('*' == *accept_pattern) ) ||
+      ( (da - accept_pattern == dm - mime) &&
+        (0 == strncasecmp (accept_pattern,
+                           mime,
+                           da - accept_pattern)) ) ) &&
+    ( (0 == strcmp (da, "/*")) ||
+      (0 == strcasecmp (da,
+                        dm)) );
+}
+
+
+/**
+ * Check if @a lang matches the @a language_pattern, and if so with
+ * which preference.
+ *
+ * @param language_pattern a language preferences string
+ *        like "fr-CH, fr;q=0.9, en;q=0.8, *;q=0.1"
+ * @param lang the 2-digit language to match
+ * @return q-weight given for @a lang in @a language_pattern, 1.0 if no 
weights are given;
+ *         0 if @a lang is not in @a language_pattern
+ */
+static double
+language_matches (const char *language_pattern,
+                  const char *lang)
+{
+  char *p = GNUNET_strdup (language_pattern);
+  char *sptr;
+  double r = 0.0;
+
+  for (char *tok = strtok_r (p, ", ", &sptr);
+       NULL != tok;
+       tok = strtok_r (NULL, ", ", &sptr))
+  {
+    char *sptr2;
+    char *lp = strtok_r (tok, ";", &sptr2);
+    char *qp = strtok_r (NULL, ";", &sptr2);
+    double q = 1.0;
+
+    GNUNET_break_op ( (NULL == qp) ||
+                      (1 == sscanf (qp,
+                                    "q=%lf",
+                                    &q)) );
+    if (0 == strcasecmp (lang,
+                         lp))
+      r = GNUNET_MAX (r, q);
+  }
+  GNUNET_free (p);
+  return r;
+}
+
+
+/**
+ * Handle a "/terms" request.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TEH_handler_terms (struct TEH_RequestHandler *rh,
+                   struct MHD_Connection *connection,
+                   void **connection_cls,
+                   const char *upload_data,
+                   size_t *upload_data_size)
+{
+  struct MHD_Response *resp;
+  struct Terms *t;
+
+  (void) rh;
+  (void) upload_data;
+  (void) upload_data_size;
+  (void) connection_cls;
+  {
+    const char *etag;
+
+    etag = MHD_lookup_connection_value (connection,
+                                        MHD_HEADER_KIND,
+                                        MHD_HTTP_HEADER_IF_NONE_MATCH);
+    if ( (NULL != etag) &&
+         (0 == strcasecmp (etag,
+                           terms_etag)) )
+    {
+      int ret;
+
+      resp = MHD_create_response_from_buffer (0,
+                                              NULL,
+                                              MHD_RESPMEM_PERSISTENT);
+      ret = MHD_queue_response (connection,
+                                MHD_HTTP_NOT_MODIFIED,
+                                resp);
+      GNUNET_break (MHD_YES == ret);
+      MHD_destroy_response (resp);
+      return ret;
+    }
+  }
+
+  t = NULL;
+  {
+    const char *mime;
+    const char *lang;
+
+    mime = MHD_lookup_connection_value (connection,
+                                        MHD_HEADER_KIND,
+                                        MHD_HTTP_HEADER_ACCEPT);
+    if (NULL == mime)
+      mime = "text/html";
+    lang = MHD_lookup_connection_value (connection,
+                                        MHD_HEADER_KIND,
+                                        MHD_HTTP_HEADER_ACCEPT_LANGUAGE);
+    if (NULL == mime)
+      mime = "text/html";
+    /* Find best match: must match mime type (if possible), and if
+       mime type matches, ideally also language */
+    for (unsigned int i = 0; NULL != terms[i].terms; i++)
+    {
+      struct Terms *p = &terms[i];
+
+      if ( (NULL == t) ||
+           (mime_matches (mime,
+                          p->mime_type)) )
+      {
+        if ( (NULL == t) ||
+             (language_matches (lang,
+                                p->mime_type) >
+              language_matches (lang,
+                                t->mime_type) ) )
+          t = p;
+      }
+    }
+  }
+
+  if (NULL == t)
+  {
+    /* Default terms of service if none are configured */
+    static struct Terms none = {
+      .mime_type = "text/plain",
+      .terms = "Terms of service not configured",
+      .language = "en",
+      .terms_size = sizeof ("Terms of service not configured")
+    };
+    t = &none;
+  }
+
+  /* try to compress the response */
+  resp = NULL;
+  if (MHD_YES ==
+      TALER_MHD_can_compress (connection))
+  {
+    void *buf = GNUNET_memdup (t->terms,
+                               t->terms_size);
+    size_t buf_size = t->terms_size;
+
+    if (TALER_MHD_body_compress (&buf,
+                                 &buf_size))
+    {
+      resp = MHD_create_response_from_buffer (buf_size,
+                                              buf,
+                                              MHD_RESPMEM_MUST_FREE);
+      if (MHD_NO ==
+          MHD_add_response_header (resp,
+                                   MHD_HTTP_HEADER_CONTENT_ENCODING,
+                                   "deflate"))
+      {
+        GNUNET_break (0);
+        MHD_destroy_response (resp);
+        resp = NULL;
+      }
+    }
+    else
+    {
+      GNUNET_free (buf);
+    }
+  }
+  if (NULL == resp)
+  {
+    /* could not generate compressed response, return uncompressed */
+    resp = MHD_create_response_from_buffer (t->terms_size,
+                                            (void *) t->terms,
+                                            MHD_RESPMEM_PERSISTENT);
+  }
+  GNUNET_break (MHD_YES ==
+                MHD_add_response_header (resp,
+                                         MHD_HTTP_HEADER_ETAG,
+                                         terms_etag));
+  GNUNET_break (MHD_YES ==
+                MHD_add_response_header (resp,
+                                         MHD_HTTP_HEADER_CONTENT_TYPE,
+                                         t->mime_type));
+  {
+    int ret;
+
+    ret = MHD_queue_response (connection,
+                              MHD_HTTP_OK,
+                              resp);
+    MHD_destroy_response (resp);
+    return ret;
+  }
+}
+
+
+/**
+ * Load all the terms of service from @a path under language @a lang
+ * from file @a name
+ *
+ * @param path where the terms are found
+ * @param lang which language directory to crawl
+ * @param name specific file to access
+ */
+static void
+load_terms (const char *path,
+            const char *lang,
+            const char *name)
+{
+  static struct MimeMap
+  {
+    const char *ext;
+    const char *mime;
+  } mm[] = {
+    { .ext = "html", .mime = "text/html" },
+    { .ext = NULL, .mime = NULL }
+  };
+  const char *ext = strrchr (name, '.');
+  const char *mime;
+
+  if (NULL == ext)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Unsupported file `%s' in directory `%s/%s': lacks 
extension\n",
+                name,
+                path,
+                lang);
+    return;
+  }
+  mime = NULL;
+  for (unsigned int i = 0; NULL != mm[i].ext; i++)
+    if (0 == strcasecmp (mm[i].ext,
+                         ext))
+    {
+      mime = mm[i].mime;
+      break;
+    }
+  if (NULL == mime)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "Unsupported file extension `%s' of file `%s' in directory 
`%s/%s'\n",
+                ext,
+                name,
+                path,
+                lang);
+    return;
+  }
+  /* try to read the file with the terms of service */
+  {
+    struct stat st;
+    char *fn;
+    int fd;
+
+    GNUNET_asprintf (&fn,
+                     "%s/%s/%s",
+                     path,
+                     lang,
+                     name);
+    fd = open (fn, O_RDONLY);
+    if (-1 == fd)
+    {
+      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
+                                "open",
+                                fn);
+      GNUNET_free (fn);
+      return;
+    }
+    GNUNET_free (fn);
+    if (0 != fstat (fd, &st))
+    {
+      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
+                                "fstat",
+                                fn);
+      (void) close (fd);
+      GNUNET_free (fn);
+      return;
+    }
+    if (SIZE_MAX < st.st_size)
+    {
+      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
+                                "fstat-size",
+                                fn);
+      (void) close (fd);
+      GNUNET_free (fn);
+      return;
+    }
+    {
+      char *buf;
+      size_t bsize;
+      ssize_t ret;
+
+      bsize = (size_t) st.st_size;
+      buf = GNUNET_malloc_large (bsize);
+      if (NULL == buf)
+      {
+        GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+                             "malloc");
+        (void) close (fd);
+        GNUNET_free (fn);
+        return;
+      }
+      ret = read (fd,
+                  buf,
+                  bsize);
+      if ( (ret < 0) ||
+           (bsize != ((size_t) ret)) )
+      {
+        GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
+                                  "read",
+                                  fn);
+        (void) close (fd);
+        GNUNET_free (buf);
+        GNUNET_free (fn);
+        return;
+      }
+      (void) close (fd);
+      GNUNET_free (fn);
+
+      /* append to global list of terms of service */
+      {
+        struct Terms t = {
+          .mime_type = mime,
+          .terms = buf,
+          .language = lang,
+          .terms_size = bsize
+        };
+
+        GNUNET_array_append (terms,
+                             terms_len,
+                             t);
+      }
+    }
+  }
+}
+
+
+/**
+ * Load all the terms of service from @a path under language @a lang.
+ *
+ * @param path where the terms are found
+ * @param lang which language directory to crawl
+ */
+static void
+load_language (const char *path,
+               const char *lang)
+{
+  char *dname;
+  DIR *d;
+
+  GNUNET_asprintf (&dname,
+                   "%s/%s",
+                   path,
+                   lang);
+  d = opendir (dname);
+  for (struct dirent *de = readdir (d);
+       NULL != de;
+       de = readdir (d))
+  {
+    const char *fn = de->d_name;
+
+    if (fn[0] == '.')
+      continue;
+    load_terms (path, lang, fn);
+  }
+  closedir (d);
+  free (dname);
+}
+
+
+/**
+ * Load our terms of service as per configuration.
+ *
+ * @param cfg configuration to process
+ */
+void
+TEH_load_terms (const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+  char *path;
+  DIR *d;
+
+  if (GNUNET_OK !=
+      GNUNET_CONFIGURATION_get_value_filename (cfg,
+                                               "exchange",
+                                               "terms",
+                                               &path))
+  {
+    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
+                               "exchange",
+                               "TERMS");
+
+    return;
+  }
+  d = opendir (path);
+  for (struct dirent *de = readdir (d);
+       NULL != de;
+       de = readdir (d))
+  {
+    const char *lang = de->d_name;
+
+    if (lang[0] == '.')
+      continue;
+    load_language (path, lang);
+  }
+  closedir (d);
+  free (path);
+}
+
+
+/* end of taler-exchange-httpd_terms.c */
diff --git a/src/exchange/taler-exchange-httpd_terms.h 
b/src/exchange/taler-exchange-httpd_terms.h
new file mode 100644
index 00000000..1cfd8239
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_terms.h
@@ -0,0 +1,49 @@
+/*
+  This file is part of TALER
+  Copyright (C) 2019 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-exchange-httpd_terms.h
+ * @brief Handle /terms requests to return the terms of service
+ * @author Christian Grothoff
+ */
+#ifndef TALER_EXCHANGE_HTTPD_TERMS_H
+#define TALER_EXCHANGE_HTTPD_TERMS_H
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_json_lib.h>
+#include <jansson.h>
+#include <microhttpd.h>
+#include "taler_mhd_lib.h"
+#include "taler-exchange-httpd_responses.h"
+
+
+/**
+ * Handle a "/terms" request.
+ *
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] connection_cls the connection's closure (can be updated)
+ * @param upload_data upload data
+ * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
+ * @return MHD result code
+ */
+int
+TEH_handler_terms (struct TEH_RequestHandler *rh,
+                   struct MHD_Connection *connection,
+                   void **connection_cls,
+                   const char *upload_data,
+                   size_t *upload_data_size);
+
+#endif

-- 
To stop receiving notification emails like this one, please contact
address@hidden.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]