LCOV - code coverage report
Current view: top level - sync - sync-httpd_backup.c (source / functions) Hit Total Coverage
Test: GNU Taler sync coverage report Lines: 29 74 39.2 %
Date: 2021-08-30 06:54:48 Functions: 2 2 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2019 Taler Systems SA
       4             : 
       5             :   TALER is free software; you can redistribute it and/or modify it under the
       6             :   terms of the GNU Affero 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 MERCHANTABILITY or FITNESS FOR
      11             :   A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
      12             : 
      13             :   You should have received a copy of the GNU Affero General Public License along with
      14             :   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
      15             : */
      16             : /**
      17             :  * @file sync-httpd_backup.c
      18             :  * @brief functions to handle incoming requests for backups
      19             :  * @author Christian Grothoff
      20             :  */
      21             : #include "platform.h"
      22             : #include "sync-httpd.h"
      23             : #include <gnunet/gnunet_util_lib.h>
      24             : #include "sync-httpd_backup.h"
      25             : 
      26             : 
      27             : /**
      28             :  * Handle request on @a connection for retrieval of the latest
      29             :  * backup of @a account.
      30             :  *
      31             :  * @param connection the MHD connection to handle
      32             :  * @param account public key of the account the request is for
      33             :  * @return MHD result code
      34             :  */
      35             : MHD_RESULT
      36           3 : SH_backup_get (struct MHD_Connection *connection,
      37             :                const struct SYNC_AccountPublicKeyP *account)
      38             : {
      39             :   struct GNUNET_HashCode backup_hash;
      40             :   enum SYNC_DB_QueryStatus qs;
      41             :   MHD_RESULT ret;
      42             : 
      43           3 :   qs = db->lookup_account_TR (db->cls,
      44             :                               account,
      45             :                               &backup_hash);
      46           3 :   switch (qs)
      47             :   {
      48           0 :   case SYNC_DB_OLD_BACKUP_MISSING:
      49           0 :     GNUNET_break (0);
      50           0 :     return TALER_MHD_reply_with_error (connection,
      51             :                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
      52             :                                        TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
      53             :                                        NULL);
      54           0 :   case SYNC_DB_OLD_BACKUP_MISMATCH:
      55           0 :     GNUNET_break (0);
      56           0 :     return TALER_MHD_reply_with_error (connection,
      57             :                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
      58             :                                        TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
      59             :                                        NULL);
      60           1 :   case SYNC_DB_PAYMENT_REQUIRED:
      61           1 :     return TALER_MHD_reply_with_error (connection,
      62             :                                        MHD_HTTP_NOT_FOUND,
      63             :                                        TALER_EC_SYNC_ACCOUNT_UNKNOWN,
      64             :                                        NULL);
      65           0 :   case SYNC_DB_HARD_ERROR:
      66           0 :     return TALER_MHD_reply_with_error (connection,
      67             :                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
      68             :                                        TALER_EC_GENERIC_DB_FETCH_FAILED,
      69             :                                        NULL);
      70           0 :   case SYNC_DB_SOFT_ERROR:
      71           0 :     GNUNET_break (0);
      72           0 :     return TALER_MHD_reply_with_error (connection,
      73             :                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
      74             :                                        TALER_EC_GENERIC_DB_SOFT_FAILURE,
      75             :                                        NULL);
      76           0 :   case SYNC_DB_NO_RESULTS:
      77             :     {
      78             :       struct MHD_Response *resp;
      79             : 
      80           0 :       resp = MHD_create_response_from_buffer (0,
      81             :                                               NULL,
      82             :                                               MHD_RESPMEM_PERSISTENT);
      83           0 :       TALER_MHD_add_global_headers (resp);
      84           0 :       ret = MHD_queue_response (connection,
      85             :                                 MHD_HTTP_NO_CONTENT,
      86             :                                 resp);
      87           0 :       MHD_destroy_response (resp);
      88             :     }
      89           0 :     return ret;
      90           2 :   case SYNC_DB_ONE_RESULT:
      91             :     {
      92             :       const char *inm;
      93             : 
      94           2 :       inm = MHD_lookup_connection_value (connection,
      95             :                                          MHD_HEADER_KIND,
      96             :                                          MHD_HTTP_HEADER_IF_NONE_MATCH);
      97           2 :       if (NULL != inm)
      98             :       {
      99             :         struct GNUNET_HashCode inm_h;
     100             : 
     101           0 :         if (GNUNET_OK !=
     102           0 :             GNUNET_STRINGS_string_to_data (inm,
     103             :                                            strlen (inm),
     104             :                                            &inm_h,
     105             :                                            sizeof (inm_h)))
     106             :         {
     107           0 :           GNUNET_break_op (0);
     108           0 :           return TALER_MHD_reply_with_error (connection,
     109             :                                              MHD_HTTP_BAD_REQUEST,
     110             :                                              TALER_EC_SYNC_BAD_IF_NONE_MATCH,
     111             :                                              "Etag does not include a base32-encoded SHA-512 hash");
     112             :         }
     113           0 :         if (0 == GNUNET_memcmp (&inm_h,
     114             :                                 &backup_hash))
     115             :         {
     116             :           struct MHD_Response *resp;
     117             : 
     118           0 :           resp = MHD_create_response_from_buffer (0,
     119             :                                                   NULL,
     120             :                                                   MHD_RESPMEM_PERSISTENT);
     121           0 :           TALER_MHD_add_global_headers (resp);
     122           0 :           ret = MHD_queue_response (connection,
     123             :                                     MHD_HTTP_NOT_MODIFIED,
     124             :                                     resp);
     125           0 :           MHD_destroy_response (resp);
     126           0 :           return ret;
     127             :         }
     128             :       }
     129             :     }
     130             :     /* We have a result, should fetch and return it! */
     131           2 :     break;
     132             :   }
     133           2 :   return SH_return_backup (connection,
     134             :                            account,
     135             :                            MHD_HTTP_OK);
     136             : }
     137             : 
     138             : 
     139             : /**
     140             :  * Return the current backup of @a account on @a connection
     141             :  * using @a default_http_status on success.
     142             :  *
     143             :  * @param connection MHD connection to use
     144             :  * @param account account to query
     145             :  * @param default_http_status HTTP status to queue response
     146             :  *  with on success (#MHD_HTTP_OK or #MHD_HTTP_CONFLICT)
     147             :  * @return MHD result code
     148             :  */
     149             : MHD_RESULT
     150           3 : SH_return_backup (struct MHD_Connection *connection,
     151             :                   const struct SYNC_AccountPublicKeyP *account,
     152             :                   unsigned int default_http_status)
     153             : {
     154             :   enum SYNC_DB_QueryStatus qs;
     155             :   struct MHD_Response *resp;
     156             :   MHD_RESULT ret;
     157             :   struct SYNC_AccountSignatureP account_sig;
     158             :   struct GNUNET_HashCode backup_hash;
     159             :   struct GNUNET_HashCode prev_hash;
     160             :   size_t backup_size;
     161             :   void *backup;
     162             : 
     163           3 :   qs = db->lookup_backup_TR (db->cls,
     164             :                              account,
     165             :                              &account_sig,
     166             :                              &prev_hash,
     167             :                              &backup_hash,
     168             :                              &backup_size,
     169             :                              &backup);
     170           3 :   switch (qs)
     171             :   {
     172           0 :   case SYNC_DB_OLD_BACKUP_MISSING:
     173           0 :     GNUNET_break (0);
     174           0 :     return TALER_MHD_reply_with_error (connection,
     175             :                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
     176             :                                        TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
     177             :                                        "unexpected return status (backup missing)");
     178           0 :   case SYNC_DB_OLD_BACKUP_MISMATCH:
     179           0 :     GNUNET_break (0);
     180           0 :     return TALER_MHD_reply_with_error (connection,
     181             :                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
     182             :                                        TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
     183             :                                        "unexpected return status (backup mismatch)");
     184           0 :   case SYNC_DB_PAYMENT_REQUIRED:
     185           0 :     GNUNET_break (0);
     186           0 :     return TALER_MHD_reply_with_error (connection,
     187             :                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
     188             :                                        TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
     189             :                                        "unexpected return status (payment required)");
     190           0 :   case SYNC_DB_HARD_ERROR:
     191           0 :     GNUNET_break (0);
     192           0 :     return TALER_MHD_reply_with_error (connection,
     193             :                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
     194             :                                        TALER_EC_GENERIC_DB_FETCH_FAILED,
     195             :                                        NULL);
     196           0 :   case SYNC_DB_SOFT_ERROR:
     197           0 :     GNUNET_break (0);
     198           0 :     return TALER_MHD_reply_with_error (connection,
     199             :                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
     200             :                                        TALER_EC_GENERIC_DB_SOFT_FAILURE,
     201             :                                        NULL);
     202           0 :   case SYNC_DB_NO_RESULTS:
     203           0 :     GNUNET_break (0);
     204             :     /* Note: can theoretically happen due to non-transactional nature if
     205             :        the backup expired / was gc'ed JUST between the two SQL calls.
     206             :        But too rare to handle properly, as doing a transaction would be
     207             :        expensive. Just admit to failure ;-) */
     208           0 :     return TALER_MHD_reply_with_error (connection,
     209             :                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
     210             :                                        TALER_EC_GENERIC_DB_INVARIANT_FAILURE,
     211             :                                        NULL);
     212           3 :   case SYNC_DB_ONE_RESULT:
     213             :     /* interesting case below */
     214           3 :     break;
     215             :   }
     216           3 :   resp = MHD_create_response_from_buffer (backup_size,
     217             :                                           backup,
     218             :                                           MHD_RESPMEM_MUST_FREE);
     219           3 :   TALER_MHD_add_global_headers (resp);
     220             :   {
     221             :     char *sig_s;
     222             :     char *prev_s;
     223             :     char *etag;
     224             : 
     225           3 :     sig_s = GNUNET_STRINGS_data_to_string_alloc (&account_sig,
     226             :                                                  sizeof (account_sig));
     227           3 :     prev_s = GNUNET_STRINGS_data_to_string_alloc (&prev_hash,
     228             :                                                   sizeof (prev_hash));
     229           3 :     etag = GNUNET_STRINGS_data_to_string_alloc (&backup_hash,
     230             :                                                 sizeof (backup_hash));
     231           3 :     GNUNET_break (MHD_YES ==
     232             :                   MHD_add_response_header (resp,
     233             :                                            "Sync-Signature",
     234             :                                            sig_s));
     235           3 :     GNUNET_break (MHD_YES ==
     236             :                   MHD_add_response_header (resp,
     237             :                                            "Sync-Previous",
     238             :                                            prev_s));
     239           3 :     GNUNET_break (MHD_YES ==
     240             :                   MHD_add_response_header (resp,
     241             :                                            MHD_HTTP_HEADER_ETAG,
     242             :                                            etag));
     243           3 :     GNUNET_free (etag);
     244           3 :     GNUNET_free (prev_s);
     245           3 :     GNUNET_free (sig_s);
     246             :   }
     247           3 :   ret = MHD_queue_response (connection,
     248             :                             default_http_status,
     249             :                             resp);
     250           3 :   MHD_destroy_response (resp);
     251           3 :   return ret;
     252             : }

Generated by: LCOV version 1.14