LCOV - code coverage report
Current view: top level - lib - sync_api_download.c (source / functions) Hit Total Coverage
Test: GNU Taler coverage report Lines: 0 92 0.0 %
Date: 2020-10-21 06:15:51 Functions: 0 4 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2014-2019 Taler Systems SA
       4             : 
       5             :   TALER is free software; you can redistribute it and/or modify
       6             :   it under the terms of the GNU Lesser General Public License as
       7             :   published by the Free Software Foundation; either version 2.1,
       8             :   or (at your option) any later version.
       9             : 
      10             :   TALER is distributed in the hope that it will be useful, but
      11             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             :   GNU Lesser General Public License for more details.
      14             : 
      15             :   You should have received a copy of the GNU Lesser General Public
      16             :   License along with TALER; see the file COPYING.LGPL.  If not,
      17             :   see <http://www.gnu.org/licenses/>
      18             : */
      19             : 
      20             : /**
      21             :  * @file lib/sync_api_download.c
      22             :  * @brief Implementation of the download
      23             :  * @author Christian Grothoff
      24             :  */
      25             : #include "platform.h"
      26             : #include <curl/curl.h>
      27             : #include <jansson.h>
      28             : #include <microhttpd.h> /* just for HTTP status codes */
      29             : #include <gnunet/gnunet_util_lib.h>
      30             : #include <gnunet/gnunet_curl_lib.h>
      31             : #include <taler/taler_signatures.h>
      32             : #include "sync_service.h"
      33             : #include "sync_api_curl_defaults.h"
      34             : 
      35             : 
      36             : /**
      37             :  * @brief Handle for a download operation.
      38             :  */
      39             : struct SYNC_DownloadOperation
      40             : {
      41             : 
      42             :   /**
      43             :    * The url for this request.
      44             :    */
      45             :   char *url;
      46             : 
      47             :   /**
      48             :    * Handle for the request.
      49             :    */
      50             :   struct GNUNET_CURL_Job *job;
      51             : 
      52             :   /**
      53             :    * Reference to the execution context.
      54             :    */
      55             :   struct GNUNET_CURL_Context *ctx;
      56             : 
      57             :   /**
      58             :    * Function to call with the result.
      59             :    */
      60             :   SYNC_DownloadCallback cb;
      61             : 
      62             :   /**
      63             :    * Closure for @e cb.
      64             :    */
      65             :   void *cb_cls;
      66             : 
      67             :   /**
      68             :    * Public key of the account we are downloading from.
      69             :    */
      70             :   struct SYNC_AccountPublicKeyP account_pub;
      71             : 
      72             :   /**
      73             :    * Signature returned in the "Sync-Signature"
      74             :    * header, or all zeros for none.
      75             :    */
      76             :   struct SYNC_AccountSignatureP account_sig;
      77             : 
      78             :   /**
      79             :    * Hash code returned by the server in the
      80             :    * "Sync-Previous" header, or all zeros for
      81             :    * none.
      82             :    */
      83             :   struct GNUNET_HashCode sync_previous;
      84             : 
      85             : };
      86             : 
      87             : 
      88             : /**
      89             :  * Function called when we're done processing the
      90             :  * HTTP /backup request.
      91             :  *
      92             :  * @param cls the `struct SYNC_DownloadOperation`
      93             :  * @param response_code HTTP response code, 0 on error
      94             :  * @param response
      95             :  */
      96             : static void
      97           0 : handle_download_finished (void *cls,
      98             :                           long response_code,
      99             :                           const void *data,
     100             :                           size_t data_size)
     101             : {
     102           0 :   struct SYNC_DownloadOperation *download = cls;
     103             : 
     104           0 :   download->job = NULL;
     105           0 :   switch (response_code)
     106             :   {
     107           0 :   case 0:
     108           0 :     break;
     109           0 :   case MHD_HTTP_OK:
     110             :     {
     111             :       struct SYNC_DownloadDetails dd;
     112           0 :       struct SYNC_UploadSignaturePS usp = {
     113           0 :         .purpose.purpose = htonl (TALER_SIGNATURE_SYNC_BACKUP_UPLOAD),
     114           0 :         .purpose.size = htonl (sizeof (usp)),
     115             :         .old_backup_hash = download->sync_previous
     116             :       };
     117             : 
     118           0 :       GNUNET_CRYPTO_hash (data,
     119             :                           data_size,
     120             :                           &usp.new_backup_hash);
     121           0 :       if (GNUNET_OK !=
     122           0 :           GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_SYNC_BACKUP_UPLOAD,
     123             :                                       &usp,
     124             :                                       &download->account_sig.eddsa_sig,
     125             :                                       &download->account_pub.eddsa_pub))
     126             :       {
     127           0 :         GNUNET_break_op (0);
     128           0 :         response_code = 0;
     129           0 :         break;
     130             :       }
     131             :       /* Success, call callback with all details! */
     132           0 :       memset (&dd, 0, sizeof (dd));
     133           0 :       dd.sig = download->account_sig;
     134           0 :       dd.prev_backup_hash = download->sync_previous;
     135           0 :       dd.curr_backup_hash = usp.new_backup_hash;
     136           0 :       dd.backup = data;
     137           0 :       dd.backup_size = data_size;
     138           0 :       download->cb (download->cb_cls,
     139             :                     response_code,
     140             :                     &dd);
     141           0 :       download->cb = NULL;
     142           0 :       SYNC_download_cancel (download);
     143           0 :       return;
     144             :     }
     145           0 :   case MHD_HTTP_BAD_REQUEST:
     146             :     /* This should never happen, either us or the sync server is buggy
     147             :        (or API version conflict); just pass JSON reply to the application */
     148           0 :     break;
     149           0 :   case MHD_HTTP_NOT_FOUND:
     150             :     /* Nothing really to verify */
     151           0 :     break;
     152           0 :   case MHD_HTTP_INTERNAL_SERVER_ERROR:
     153             :     /* Server had an internal issue; we should retry, but this API
     154             :        leaves this to the application */
     155           0 :     break;
     156           0 :   default:
     157             :     /* unexpected response code */
     158           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     159             :                 "Unexpected response code %u\n",
     160             :                 (unsigned int) response_code);
     161           0 :     GNUNET_break (0);
     162           0 :     response_code = 0;
     163           0 :     break;
     164             :   }
     165           0 :   if (NULL != download->cb)
     166             :   {
     167           0 :     download->cb (download->cb_cls,
     168             :                   response_code,
     169             :                   NULL);
     170           0 :     download->cb = NULL;
     171             :   }
     172           0 :   SYNC_download_cancel (download);
     173             : }
     174             : 
     175             : 
     176             : /**
     177             :  * Handle HTTP header received by curl.
     178             :  *
     179             :  * @param buffer one line of HTTP header data
     180             :  * @param size size of an item
     181             :  * @param nitems number of items passed
     182             :  * @param userdata our `struct SYNC_DownloadOperation *`
     183             :  * @return `size * nitems`
     184             :  */
     185             : static size_t
     186           0 : handle_header (char *buffer,
     187             :                size_t size,
     188             :                size_t nitems,
     189             :                void *userdata)
     190             : {
     191           0 :   struct SYNC_DownloadOperation *download = userdata;
     192           0 :   size_t total = size * nitems;
     193             :   char *ndup;
     194             :   const char *hdr_type;
     195             :   char *hdr_val;
     196             :   char *sp;
     197             : 
     198           0 :   ndup = GNUNET_strndup (buffer,
     199             :                          total);
     200           0 :   hdr_type = strtok_r (ndup,
     201             :                        ":",
     202             :                        &sp);
     203           0 :   if (NULL == hdr_type)
     204             :   {
     205           0 :     GNUNET_free (ndup);
     206           0 :     return total;
     207             :   }
     208           0 :   hdr_val = strtok_r (NULL,
     209             :                       "\n\r",
     210             :                       &sp);
     211           0 :   if (NULL == hdr_val)
     212             :   {
     213           0 :     GNUNET_free (ndup);
     214           0 :     return total;
     215             :   }
     216           0 :   if (' ' == *hdr_val)
     217           0 :     hdr_val++;
     218           0 :   if (0 == strcasecmp (hdr_type,
     219             :                        "Sync-Signature"))
     220             :   {
     221           0 :     if (GNUNET_OK !=
     222           0 :         GNUNET_STRINGS_string_to_data (hdr_val,
     223             :                                        strlen (hdr_val),
     224           0 :                                        &download->account_sig,
     225             :                                        sizeof (struct SYNC_AccountSignatureP)))
     226             :     {
     227           0 :       GNUNET_break_op (0);
     228           0 :       GNUNET_free (ndup);
     229           0 :       return 0;
     230             :     }
     231             :   }
     232           0 :   if (0 == strcasecmp (hdr_type,
     233             :                        "Sync-Previous"))
     234             :   {
     235           0 :     if (GNUNET_OK !=
     236           0 :         GNUNET_STRINGS_string_to_data (hdr_val,
     237             :                                        strlen (hdr_val),
     238           0 :                                        &download->sync_previous,
     239             :                                        sizeof (struct GNUNET_HashCode)))
     240             :     {
     241           0 :       GNUNET_break_op (0);
     242           0 :       GNUNET_free (ndup);
     243           0 :       return 0;
     244             :     }
     245             :   }
     246           0 :   GNUNET_free (ndup);
     247           0 :   return total;
     248             : }
     249             : 
     250             : 
     251             : /**
     252             :  * Download the latest version of a backup for account @a pub.
     253             :  *
     254             :  * @param ctx for HTTP client request processing
     255             :  * @param base_url base URL of the Sync server
     256             :  * @param pub account public key
     257             :  * @param cb function to call with the backup
     258             :  * @param cb_cls closure for @a cb
     259             :  * @return handle for the operation
     260             :  */
     261             : struct SYNC_DownloadOperation *
     262           0 : SYNC_download (struct GNUNET_CURL_Context *ctx,
     263             :                const char *base_url,
     264             :                const struct SYNC_AccountPublicKeyP *pub,
     265             :                SYNC_DownloadCallback cb,
     266             :                void *cb_cls)
     267             : {
     268             :   struct SYNC_DownloadOperation *download;
     269             :   char *pub_str;
     270             :   CURL *eh;
     271             : 
     272           0 :   download = GNUNET_new (struct SYNC_DownloadOperation);
     273           0 :   download->account_pub = *pub;
     274           0 :   pub_str = GNUNET_STRINGS_data_to_string_alloc (pub,
     275             :                                                  sizeof (*pub));
     276           0 :   GNUNET_asprintf (&download->url,
     277             :                    "%s%sbackups/%s",
     278             :                    base_url,
     279           0 :                    '/' == base_url[strlen (base_url) - 1]
     280             :                    ? ""
     281             :                    : "/",
     282             :                    pub_str);
     283           0 :   GNUNET_free (pub_str);
     284           0 :   eh = SYNC_curl_easy_get_ (download->url);
     285           0 :   GNUNET_assert (CURLE_OK ==
     286             :                  curl_easy_setopt (eh,
     287             :                                    CURLOPT_HEADERFUNCTION,
     288             :                                    &handle_header));
     289           0 :   GNUNET_assert (CURLE_OK ==
     290             :                  curl_easy_setopt (eh,
     291             :                                    CURLOPT_HEADERDATA,
     292             :                                    download));
     293           0 :   download->cb = cb;
     294           0 :   download->cb_cls = cb_cls;
     295           0 :   download->job = GNUNET_CURL_job_add_raw (ctx,
     296             :                                            eh,
     297             :                                            GNUNET_NO,
     298             :                                            &handle_download_finished,
     299             :                                            download);
     300           0 :   return download;
     301             : }
     302             : 
     303             : 
     304             : /**
     305             :  * Cancel the download.
     306             :  *
     307             :  * @param do operation to cancel.
     308             :  */
     309             : void
     310           0 : SYNC_download_cancel (struct SYNC_DownloadOperation *download)
     311             : {
     312           0 :   if (NULL != download->job)
     313             :   {
     314           0 :     GNUNET_CURL_job_cancel (download->job);
     315           0 :     download->job = NULL;
     316             :   }
     317           0 :   GNUNET_free (download->url);
     318           0 :   GNUNET_free (download);
     319           0 : }
     320             : 
     321             : 
     322             : /* end of sync_api_download.c */

Generated by: LCOV version 1.14