LCOV - code coverage report
Current view: top level - lib - merchant_api_tip_authorize.c (source / functions) Hit Total Coverage
Test: rcoverage.info Lines: 44 64 68.8 %
Date: 2018-09-19 06:18:31 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2014-2017 Taler Systems SA
       4             : 
       5             :   TALER is free software; you can redistribute it and/or modify it under the
       6             :   terms of the GNU Lesser General Public License as published by the Free Software
       7             :   Foundation; either version 2.1, 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 Lesser General Public License for more details.
      12             : 
      13             :   You should have received a copy of the GNU Lesser General Public License along with
      14             :   TALER; see the file COPYING.LGPL.  If not, see
      15             :   <http://www.gnu.org/licenses/>
      16             : */
      17             : /**
      18             :  * @file lib/merchant_api_tip_authorize.c
      19             :  * @brief Implementation of the /tip-authorize request of the merchant's HTTP API
      20             :  * @author Marcello Stanisci
      21             :  * @author Christian Grothoff
      22             :  */
      23             : #include "platform.h"
      24             : #include <curl/curl.h>
      25             : #include <jansson.h>
      26             : #include <microhttpd.h> /* just for HTTP status codes */
      27             : #include <gnunet/gnunet_util_lib.h>
      28             : #include <gnunet/gnunet_curl_lib.h>
      29             : #include "taler_merchant_service.h"
      30             : #include <taler/taler_json_lib.h>
      31             : #include <taler/taler_signatures.h>
      32             : 
      33             : 
      34             : /**
      35             :  * @brief A handle for tracking transactions.
      36             :  */
      37             : struct TALER_MERCHANT_TipAuthorizeOperation
      38             : {
      39             : 
      40             :   /**
      41             :    * The url for this request.
      42             :    */
      43             :   char *url;
      44             : 
      45             :   /**
      46             :    * JSON encoding of the request to POST.
      47             :    */
      48             :   char *json_enc;
      49             : 
      50             :   /**
      51             :    * Handle for the request.
      52             :    */
      53             :   struct GNUNET_CURL_Job *job;
      54             : 
      55             :   /**
      56             :    * Function to call with the result.
      57             :    */
      58             :   TALER_MERCHANT_TipAuthorizeCallback cb;
      59             : 
      60             :   /**
      61             :    * Closure for @a cb.
      62             :    */
      63             :   void *cb_cls;
      64             : 
      65             :   /**
      66             :    * Reference to the execution context.
      67             :    */
      68             :   struct GNUNET_CURL_Context *ctx;
      69             : };
      70             : 
      71             : 
      72             : /**
      73             :  * We got a 200 response back from the exchange (or the merchant).
      74             :  * Now we need to parse the response and if it is well-formed,
      75             :  * call the callback (and set it to NULL afterwards).
      76             :  *
      77             :  * @param tao handle of the original authorization operation
      78             :  * @param json cryptographic proof returned by the exchange/merchant
      79             :  * @return #GNUNET_OK if response is valid
      80             :  */
      81             : static int
      82           6 : check_ok (struct TALER_MERCHANT_TipAuthorizeOperation *tao,
      83             :           const json_t *json)
      84             : {
      85             :   struct GNUNET_HashCode tip_id;
      86             :   struct GNUNET_TIME_Absolute tip_expiration;
      87             :   const char *exchange_url;
      88           6 :   struct GNUNET_JSON_Specification spec[] = {
      89             :     GNUNET_JSON_spec_absolute_time ("expiration", &tip_expiration),
      90             :     GNUNET_JSON_spec_fixed_auto ("tip_id", &tip_id),
      91             :     GNUNET_JSON_spec_string ("exchange_url", &exchange_url),
      92             :     GNUNET_JSON_spec_end()
      93             :   };
      94             : 
      95           6 :   if (GNUNET_OK !=
      96           6 :       GNUNET_JSON_parse (json,
      97             :                          spec,
      98             :                          NULL, NULL))
      99             :   {
     100           0 :     GNUNET_break_op (0);
     101           0 :     return GNUNET_SYSERR;
     102             :   }
     103           6 :   tao->cb (tao->cb_cls,
     104             :            MHD_HTTP_OK,
     105             :            TALER_JSON_get_error_code (json),
     106             :            &tip_id,
     107             :            tip_expiration,
     108             :            exchange_url);
     109           6 :   tao->cb = NULL; /* do not call twice */
     110           6 :   GNUNET_JSON_parse_free (spec);
     111           6 :   return GNUNET_OK;
     112             : }
     113             : 
     114             : 
     115             : /**
     116             :  * Function called when we're done processing the
     117             :  * HTTP /track/transaction request.
     118             :  *
     119             :  * @param cls the `struct TALER_MERCHANT_TipAuthorizeOperation`
     120             :  * @param response_code HTTP response code, 0 on error
     121             :  * @param json response body, NULL if not in JSON
     122             :  */
     123             : static void
     124          16 : handle_tip_authorize_finished (void *cls,
     125             :                                long response_code,
     126             :                                const json_t *json)
     127             : {
     128          16 :   struct TALER_MERCHANT_TipAuthorizeOperation *tao = cls;
     129             : 
     130          16 :   tao->job = NULL;
     131          16 :   switch (response_code)
     132             :   {
     133             :   case MHD_HTTP_OK:
     134           6 :     if (GNUNET_OK != check_ok (tao,
     135             :                               json))
     136             :     {
     137           0 :       GNUNET_break_op (0);
     138           0 :       response_code = 0;
     139             :     }
     140           6 :     break;
     141             :   case MHD_HTTP_NOT_FOUND:
     142             :     /* Well-defined status code, pass on to application! */
     143           7 :     break;
     144             :   case MHD_HTTP_PRECONDITION_FAILED:
     145             :     /* Well-defined status code, pass on to application! */
     146           3 :     break;
     147             :   case MHD_HTTP_INTERNAL_SERVER_ERROR:
     148             :     /* Server had an internal issue; we should retry, but this API
     149             :        leaves this to the application */
     150           0 :     break;
     151             :   default:
     152             :     /* unexpected response code */
     153           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     154             :                 "Unexpected response code %u\n",
     155             :                 (unsigned int) response_code);
     156           0 :     GNUNET_break (0);
     157           0 :     response_code = 0;
     158           0 :     break;
     159             :   }
     160          16 :   if (NULL != tao->cb)
     161          10 :     tao->cb (tao->cb_cls,
     162             :              response_code,
     163             :              TALER_JSON_get_error_code (json),
     164             :              NULL,
     165             :              GNUNET_TIME_UNIT_ZERO_ABS,
     166             :              NULL);
     167          16 :   TALER_MERCHANT_tip_authorize_cancel (tao);
     168          16 : }
     169             : 
     170             : 
     171             : /**
     172             :  * Issue a /tip-authorize request to the backend.  Informs the backend
     173             :  * that a tip should be created.
     174             :  *
     175             :  * @param ctx execution context
     176             :  * @param backend_url base URL of the merchant backend
     177             :  * @param pickup_url frontend URL for where the tip can be picked up
     178             :  * @param next_url where the browser should proceed after picking up the tip
     179             :  * @param amount amount to be handed out as a tip
     180             :  * @param instance which backend instance should create the tip (identifies the reserve and exchange)
     181             :  * @param justification which justification should be stored (human-readable reason for the tip)
     182             :  * @param authorize_cb callback which will work the response gotten from the backend
     183             :  * @param authorize_cb_cls closure to pass to @a authorize_cb
     184             :  * @return handle for this operation, NULL upon errors
     185             :  */
     186             : struct TALER_MERCHANT_TipAuthorizeOperation *
     187          16 : TALER_MERCHANT_tip_authorize (struct GNUNET_CURL_Context *ctx,
     188             :                               const char *backend_url,
     189             :                               const char *pickup_url,
     190             :                               const char *next_url,
     191             :                               const struct TALER_Amount *amount,
     192             :                               const char *instance,
     193             :                               const char *justification,
     194             :                               TALER_MERCHANT_TipAuthorizeCallback authorize_cb,
     195             :                               void *authorize_cb_cls)
     196             : {
     197             :   struct TALER_MERCHANT_TipAuthorizeOperation *tao;
     198             :   CURL *eh;
     199             :   json_t *te_obj;
     200             : 
     201          16 :   tao = GNUNET_new (struct TALER_MERCHANT_TipAuthorizeOperation);
     202          16 :   tao->ctx = ctx;
     203          16 :   tao->cb = authorize_cb;
     204          16 :   tao->cb_cls = authorize_cb_cls;
     205          16 :   tao->url = TALER_url_join (backend_url, "/tip-authorize", NULL);
     206          16 :   te_obj = json_pack ("{"
     207             :                       " s:o," /* amount */
     208             :                       " s:s," /* instance */
     209             :                       " s:s," /* justification */
     210             :                       " s:s," /* pickup_url */
     211             :                       " s:s," /* next_url */
     212             :                       "}",
     213             :                       "amount", TALER_JSON_from_amount (amount),
     214             :                       "instance", instance,
     215             :                       "justification", justification,
     216             :                       "pickup_url", pickup_url,
     217             :                       "next_url", next_url);
     218          16 :   if (NULL == te_obj)
     219             :   {
     220           0 :     GNUNET_break (0);
     221           0 :     GNUNET_free (tao->url);
     222           0 :     GNUNET_free (tao);
     223           0 :     return NULL;
     224             :   }
     225          16 :   if (NULL == (tao->json_enc =
     226          16 :                json_dumps (te_obj,
     227             :                            JSON_COMPACT)))
     228             :   {
     229           0 :     GNUNET_break (0);
     230           0 :     json_decref (te_obj);
     231           0 :     GNUNET_free (tao->url);
     232           0 :     GNUNET_free (tao);
     233           0 :     return NULL;
     234             :   }
     235          16 :   json_decref (te_obj);
     236          16 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     237             :               "Requesting URL '%s'\n",
     238             :               tao->url);
     239          16 :   eh = curl_easy_init ();
     240          16 :   GNUNET_assert (CURLE_OK ==
     241             :                  curl_easy_setopt (eh,
     242             :                                    CURLOPT_URL,
     243             :                                    tao->url));
     244          16 :   GNUNET_assert (CURLE_OK ==
     245             :                  curl_easy_setopt (eh,
     246             :                                    CURLOPT_POSTFIELDS,
     247             :                                    tao->json_enc));
     248          16 :   GNUNET_assert (CURLE_OK ==
     249             :                  curl_easy_setopt (eh,
     250             :                                    CURLOPT_POSTFIELDSIZE,
     251             :                                    strlen (tao->json_enc)));
     252          16 :   tao->job = GNUNET_CURL_job_add (ctx,
     253             :                                   eh,
     254             :                                   GNUNET_YES,
     255             :                                   &handle_tip_authorize_finished,
     256             :                                   tao);
     257          16 :   return tao;
     258             : }
     259             : 
     260             : 
     261             : /**
     262             :  * Cancel a /track/transaction request.  This function cannot be used
     263             :  * on a request handle if a response is already served for it.
     264             :  *
     265             :  * @param tao handle to the tracking operation being cancelled
     266             :  */
     267             : void
     268          16 : TALER_MERCHANT_tip_authorize_cancel (struct TALER_MERCHANT_TipAuthorizeOperation *tao)
     269             : {
     270          16 :   if (NULL != tao->job)
     271             :   {
     272           0 :     GNUNET_CURL_job_cancel (tao->job);
     273           0 :     tao->job = NULL;
     274             :   }
     275          16 :   GNUNET_free_non_null (tao->json_enc);
     276          16 :   GNUNET_free (tao->url);
     277          16 :   GNUNET_free (tao);
     278          16 : }
     279             : 
     280             : /* end of merchant_api_tip_authorize.c */

Generated by: LCOV version 1.13