LCOV - code coverage report
Current view: top level - mhd - mhd_spa.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 57.4 % 122 70
Test Date: 2025-12-28 14:06:02 Functions: 80.0 % 5 4

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   Copyright (C) 2020, 2023, 2024 Taler Systems SA
       4              : 
       5              :   TALER is free software; you can redistribute it and/or modify it under the
       6              :   terms of the GNU General Public License as published by the Free Software
       7              :   Foundation; either version 3, or (at your option) any later version.
       8              : 
       9              :   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
      10              :   WARRANTY; without even the implied warranty of EXCHANGEABILITY or FITNESS FOR
      11              :   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
      12              : 
      13              :   You should have received a copy of the GNU General Public License along with
      14              :   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
      15              : */
      16              : /**
      17              :  * @file mhd_spa.c
      18              :  * @brief logic to load single page apps
      19              :  * @author Christian Grothoff
      20              :  */
      21              : #include "taler/platform.h"
      22              : #include <gnunet/gnunet_util_lib.h>
      23              : #include "taler/taler_util.h"
      24              : #include "taler/taler_mhd_lib.h"
      25              : #include <gnunet/gnunet_mhd_compat.h>
      26              : 
      27              : 
      28              : /**
      29              :  * Resource from the WebUi.
      30              :  */
      31              : struct WebuiFile
      32              : {
      33              :   /**
      34              :    * Kept in a DLL.
      35              :    */
      36              :   struct WebuiFile *next;
      37              : 
      38              :   /**
      39              :    * Kept in a DLL.
      40              :    */
      41              :   struct WebuiFile *prev;
      42              : 
      43              :   /**
      44              :    * Path this resource matches.
      45              :    */
      46              :   char *path;
      47              : 
      48              :   /**
      49              :    * SPA resource, deflate compressed.
      50              :    */
      51              :   struct MHD_Response *responses[TALER_MHD_CT_MAX];
      52              : 
      53              : };
      54              : 
      55              : 
      56              : /**
      57              :  * Resource from the WebUi.
      58              :  */
      59              : struct TALER_MHD_Spa
      60              : {
      61              :   /**
      62              :    * Resources of the WebUI, kept in a DLL.
      63              :    */
      64              :   struct WebuiFile *webui_head;
      65              : 
      66              :   /**
      67              :    * Resources of the WebUI, kept in a DLL.
      68              :    */
      69              :   struct WebuiFile *webui_tail;
      70              : };
      71              : 
      72              : 
      73              : MHD_RESULT
      74            0 : TALER_MHD_spa_handler (const struct TALER_MHD_Spa *spa,
      75              :                        struct MHD_Connection *connection,
      76              :                        const char *path)
      77              : {
      78            0 :   struct WebuiFile *w = NULL;
      79              :   enum TALER_MHD_CompressionType comp;
      80              : 
      81            0 :   if ( (NULL == path) ||
      82            0 :        (0 == strcmp (path,
      83              :                      "")) )
      84            0 :     path = "index.html";
      85            0 :   for (struct WebuiFile *pos = spa->webui_head;
      86            0 :        NULL != pos;
      87            0 :        pos = pos->next)
      88            0 :     if (0 == strcmp (path,
      89            0 :                      pos->path))
      90              :     {
      91            0 :       w = pos;
      92            0 :       break;
      93              :     }
      94            0 :   if ( (NULL == w) ||
      95            0 :        (NULL == w->responses[TALER_MHD_CT_NONE]) )
      96            0 :     return TALER_MHD_reply_with_error (connection,
      97              :                                        MHD_HTTP_NOT_FOUND,
      98              :                                        TALER_EC_GENERIC_ENDPOINT_UNKNOWN,
      99              :                                        path);
     100            0 :   comp = TALER_MHD_can_compress (connection,
     101              :                                  TALER_MHD_CT_MAX - 1);
     102            0 :   GNUNET_assert (comp < TALER_MHD_CT_MAX);
     103              :   GNUNET_assert (comp >= 0);
     104            0 :   if (NULL != w->responses[comp])
     105            0 :     return MHD_queue_response (connection,
     106              :                                MHD_HTTP_OK,
     107              :                                w->responses[comp]);
     108            0 :   return MHD_queue_response (connection,
     109              :                              MHD_HTTP_OK,
     110              :                              w->responses[TALER_MHD_CT_NONE]);
     111              : }
     112              : 
     113              : 
     114              : /**
     115              :  * Function called on each file to load for the WebUI.
     116              :  *
     117              :  * @param cls the `struct TALER_MHD_Spa *` to build
     118              :  * @param dn name of the file to load
     119              :  */
     120              : static enum GNUNET_GenericReturnValue
     121          358 : build_webui (void *cls,
     122              :              const char *dn)
     123              : {
     124              :   static const struct
     125              :   {
     126              :     const char *ext;
     127              :     const char *mime;
     128              :   } mime_map[] = {
     129              :     {
     130              :       .ext = "css",
     131              :       .mime = "text/css"
     132              :     },
     133              :     {
     134              :       .ext = "html",
     135              :       .mime = "text/html"
     136              :     },
     137              :     {
     138              :       .ext = "js",
     139              :       .mime = "text/javascript"
     140              :     },
     141              :     {
     142              :       .ext = "jpg",
     143              :       .mime = "image/jpeg"
     144              :     },
     145              :     {
     146              :       .ext = "jpeg",
     147              :       .mime = "image/jpeg"
     148              :     },
     149              :     {
     150              :       .ext = "png",
     151              :       .mime = "image/png"
     152              :     },
     153              :     {
     154              :       .ext = "svg",
     155              :       .mime = "image/svg+xml"
     156              :     },
     157              :     {
     158              :       .ext = NULL,
     159              :       .mime = NULL
     160              :     },
     161              :   };
     162          358 :   struct TALER_MHD_Spa *spa = cls;
     163              :   int fd;
     164              :   struct stat sb;
     165              :   struct MHD_Response *response;
     166              :   char *ext;
     167              :   const char *mime;
     168              :   const char *slash;
     169              :   char *fn;
     170          358 :   const char *cts = NULL;
     171          358 :   enum TALER_MHD_CompressionType ct = TALER_MHD_CT_NONE;
     172              : 
     173          358 :   slash = strrchr (dn, '/');
     174          358 :   if (NULL == slash)
     175              :   {
     176            0 :     GNUNET_break (0);
     177            0 :     return GNUNET_SYSERR;
     178              :   }
     179          358 :   fd = open (dn,
     180              :              O_RDONLY);
     181          358 :   if (-1 == fd)
     182              :   {
     183            0 :     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
     184              :                               "open",
     185              :                               dn);
     186            0 :     return GNUNET_SYSERR;
     187              :   }
     188          358 :   if (0 !=
     189          358 :       fstat (fd,
     190              :              &sb))
     191              :   {
     192            0 :     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
     193              :                               "open",
     194              :                               dn);
     195            0 :     GNUNET_break (0 == close (fd));
     196            0 :     return GNUNET_SYSERR;
     197              :   }
     198              : 
     199          358 :   fn = GNUNET_strdup (slash + 1);
     200          358 :   ext = strrchr (fn,
     201              :                  '.');
     202          358 :   if (NULL == ext)
     203              :   {
     204           41 :     GNUNET_break (0 == close (fd));
     205           41 :     GNUNET_free (fn);
     206           41 :     return GNUNET_OK;
     207              :   }
     208          317 :   if (0 == strcmp (ext,
     209              :                    ".gz"))
     210              :   {
     211            0 :     cts = "gzip";
     212            0 :     ct = TALER_MHD_CT_GZIP;
     213            0 :     *ext = '\0';
     214            0 :     ext = strrchr (fn, '.');
     215              :   }
     216          317 :   if (0 == strcmp (ext,
     217              :                    ".zstd"))
     218              :   {
     219            0 :     cts = "zstd";
     220            0 :     ct = TALER_MHD_CT_ZSTD;
     221            0 :     *ext = '\0';
     222            0 :     ext = strrchr (fn, '.');
     223              :   }
     224          317 :   if (NULL == ext)
     225              :   {
     226            0 :     GNUNET_break (0 == close (fd));
     227            0 :     GNUNET_free (fn);
     228            0 :     return GNUNET_OK;
     229              :   }
     230          317 :   ext++;
     231              : 
     232          317 :   mime = NULL;
     233         1788 :   for (unsigned int i = 0; NULL != mime_map[i].ext; i++)
     234         1604 :     if (0 == strcasecmp (ext,
     235         1604 :                          mime_map[i].ext))
     236              :     {
     237          133 :       mime = mime_map[i].mime;
     238          133 :       break;
     239              :     }
     240              : 
     241          317 :   response = MHD_create_response_from_fd (
     242          317 :     sb.st_size,
     243              :     fd /* FD now owned by MHD! */);
     244          317 :   if (NULL == response)
     245              :   {
     246            0 :     GNUNET_free (fn);
     247            0 :     return GNUNET_SYSERR;
     248              :   }
     249          317 :   if ( (NULL != cts) &&
     250              :        (MHD_NO ==
     251            0 :         MHD_add_response_header (response,
     252              :                                  MHD_HTTP_HEADER_CONTENT_ENCODING,
     253              :                                  cts)) )
     254              :   {
     255            0 :     GNUNET_break (0);
     256            0 :     MHD_destroy_response (response);
     257            0 :     GNUNET_free (fn);
     258            0 :     return GNUNET_SYSERR;
     259              :   }
     260          317 :   if (NULL != mime)
     261              :   {
     262          133 :     GNUNET_break (MHD_YES ==
     263              :                   MHD_add_response_header (response,
     264              :                                            MHD_HTTP_HEADER_CONTENT_TYPE,
     265              :                                            mime));
     266              :   }
     267              : 
     268              :   {
     269              :     struct WebuiFile *w;
     270              : 
     271          317 :     for (w = spa->webui_head;
     272         1463 :          NULL != w;
     273         1146 :          w = w->next)
     274              :     {
     275         1146 :       if (0 == strcmp (fn,
     276         1146 :                        w->path))
     277            0 :         break;
     278              :     }
     279          317 :     if (NULL == w)
     280              :     {
     281          317 :       w = GNUNET_new (struct WebuiFile);
     282          317 :       w->path = fn;
     283          317 :       GNUNET_CONTAINER_DLL_insert (spa->webui_head,
     284              :                                    spa->webui_tail,
     285              :                                    w);
     286              :     }
     287              :     else
     288              :     {
     289            0 :       GNUNET_free (fn);
     290              :     }
     291          317 :     GNUNET_assert (NULL == w->responses[ct]);
     292          317 :     w->responses[ct] = response;
     293              :   }
     294          317 :   return GNUNET_OK;
     295              : }
     296              : 
     297              : 
     298              : struct TALER_MHD_Spa *
     299           41 : TALER_MHD_spa_load_dir (const char *dn)
     300              : {
     301              :   struct TALER_MHD_Spa *spa;
     302              : 
     303           41 :   spa = GNUNET_new (struct TALER_MHD_Spa);
     304           41 :   if (-1 ==
     305           41 :       GNUNET_DISK_directory_scan (dn,
     306              :                                   &build_webui,
     307              :                                   spa))
     308              :   {
     309            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     310              :                 "Failed to load WebUI from `%s'\n",
     311              :                 dn);
     312            0 :     TALER_MHD_spa_free (spa);
     313            0 :     return NULL;
     314              :   }
     315           41 :   return spa;
     316              : }
     317              : 
     318              : 
     319              : struct TALER_MHD_Spa *
     320           41 : TALER_MHD_spa_load (const struct GNUNET_OS_ProjectData *pd,
     321              :                     const char *dir)
     322              : {
     323              :   struct TALER_MHD_Spa *spa;
     324              :   char *dn;
     325              :   char *path;
     326              : 
     327           41 :   path = GNUNET_OS_installation_get_path (pd,
     328              :                                           GNUNET_OS_IPK_DATADIR);
     329           41 :   if (NULL == path)
     330              :   {
     331            0 :     GNUNET_break (0);
     332            0 :     return NULL;
     333              :   }
     334           41 :   GNUNET_asprintf (&dn,
     335              :                    "%s%s",
     336              :                    path,
     337              :                    dir);
     338           41 :   GNUNET_free (path);
     339           41 :   spa = TALER_MHD_spa_load_dir (dn);
     340           41 :   GNUNET_free (dn);
     341           41 :   return spa;
     342              : }
     343              : 
     344              : 
     345              : void
     346           41 : TALER_MHD_spa_free (struct TALER_MHD_Spa *spa)
     347              : {
     348              :   struct WebuiFile *w;
     349              : 
     350          358 :   while (NULL != (w = spa->webui_head))
     351              :   {
     352          317 :     GNUNET_CONTAINER_DLL_remove (spa->webui_head,
     353              :                                  spa->webui_tail,
     354              :                                  w);
     355          317 :     for (enum TALER_MHD_CompressionType ct = TALER_MHD_CT_NONE;
     356         1585 :          ct < TALER_MHD_CT_MAX;
     357         1268 :          ct++)
     358              :     {
     359         1268 :       if (NULL != w->responses[ct])
     360              :       {
     361          317 :         MHD_destroy_response (w->responses[ct]);
     362          317 :         w->responses[ct] = NULL;
     363              :       }
     364              :     }
     365          317 :     GNUNET_free (w->path);
     366          317 :     GNUNET_free (w);
     367              :   }
     368           41 :   GNUNET_free (spa);
     369           41 : }
        

Generated by: LCOV version 2.0-1