anastasis

Credential backup and recovery protocol and service
Log | Files | Refs | Submodules | README | LICENSE

anastasis-httpd_policy-upload.c (42017B)


      1 /*
      2   This file is part of Anastasis
      3   Copyright (C) 2021 Anastasis SARL
      4 
      5   Anastasis 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   Anastasis 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   Anastasis; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file anastasis-httpd_policy.c
     18  * @brief functions to handle incoming requests on /policy/
     19  * @author Dennis Neufeld
     20  * @author Dominik Meister
     21  * @author Christian Grothoff
     22  */
     23 #include "platform.h"
     24 struct PolicyUploadContext;
     25 #define TALER_MERCHANT_POST_PRIVATE_ORDERS_RESULT_CLOSURE struct \
     26         PolicyUploadContext
     27 #define TALER_MERCHANT_GET_PRIVATE_ORDER_RESULT_CLOSURE struct \
     28         PolicyUploadContext
     29 #include "anastasis-httpd.h"
     30 #include "anastasis-httpd_policy.h"
     31 #include "anastasis_service.h"
     32 #include <gnunet/gnunet_util_lib.h>
     33 #include <gnunet/gnunet_rest_lib.h>
     34 #include <taler/taler_json_lib.h>
     35 #include <taler/taler_merchant_service.h>
     36 #include <taler/taler_signatures.h>
     37 #include <taler/merchant/post-private-orders.h>
     38 #include <taler/merchant/get-private-orders-ORDER_ID.h>
     39 
     40 /**
     41  * How long do we hold an HTTP client connection if
     42  * we are awaiting payment before giving up?
     43  */
     44 #define CHECK_PAYMENT_GENERIC_TIMEOUT GNUNET_TIME_relative_multiply ( \
     45           GNUNET_TIME_UNIT_SECONDS, 30)
     46 
     47 
     48 /**
     49  * Context for an upload operation.
     50  */
     51 struct PolicyUploadContext
     52 {
     53 
     54   /**
     55    * Signature of the account holder.
     56    */
     57   struct ANASTASIS_AccountSignatureP account_sig;
     58 
     59   /**
     60    * Public key of the account holder.
     61    */
     62   struct ANASTASIS_CRYPTO_AccountPublicKeyP account;
     63 
     64   /**
     65    * Hash of the upload we are receiving right now (as promised
     66    * by the client, to be verified!).
     67    */
     68   struct GNUNET_HashCode new_policy_upload_hash;
     69 
     70   /**
     71    * Hash context for the upload.
     72    */
     73   struct GNUNET_HashContext *hash_ctx;
     74 
     75   /**
     76    * Kept in DLL for shutdown handling while suspended.
     77    */
     78   struct PolicyUploadContext *next;
     79 
     80   /**
     81    * Kept in DLL for shutdown handling while suspended.
     82    */
     83   struct PolicyUploadContext *prev;
     84 
     85   /**
     86    * Used while suspended for resumption.
     87    */
     88   struct MHD_Connection *con;
     89 
     90   /**
     91    * Upload, with as many bytes as we have received so far.
     92    */
     93   char *upload;
     94 
     95   /**
     96    * Meta data uploaded by the client, or NULL for none.
     97    */
     98   void *meta_data;
     99 
    100   /**
    101    * Number of bytes in @e meta_data.
    102    */
    103   size_t meta_data_size;
    104 
    105   /**
    106    * Used while we are awaiting proposal creation.
    107    */
    108   struct TALER_MERCHANT_PostPrivateOrdersHandle *po;
    109 
    110   /**
    111    * Used while we are waiting payment.
    112    */
    113   struct TALER_MERCHANT_GetPrivateOrderHandle *cpo;
    114 
    115   /**
    116    * HTTP response code to use on resume, if non-NULL.
    117    */
    118   struct MHD_Response *resp;
    119 
    120   /**
    121    * Order under which the client promised payment, or NULL.
    122    */
    123   const char *order_id;
    124 
    125   /**
    126    * Payment Identifier
    127    */
    128   struct ANASTASIS_PaymentSecretP payment_identifier;
    129 
    130   /**
    131    * Creation time of the payment record named by @e payment_identifier,
    132    * zero if there is none.  Non-zero means the client is asking about a
    133    * payment we already know, so the answer is a repeated payment request
    134    * rather than a fresh order.
    135    */
    136   struct GNUNET_TIME_Timestamp existing_pi_timestamp;
    137 
    138   /**
    139    * When does the operation timeout?
    140    */
    141   struct GNUNET_TIME_Absolute timeout;
    142 
    143   /**
    144    * How long must the account be valid?  Determines whether we should
    145    * trigger payment, and if so how much.
    146    */
    147   struct GNUNET_TIME_Timestamp end_date;
    148 
    149   /**
    150    * How long is the account already valid?
    151    * Determines how much the user needs to pay.
    152    */
    153   struct GNUNET_TIME_Timestamp paid_until;
    154 
    155   /**
    156    * Expected total upload size.
    157    */
    158   size_t upload_size;
    159 
    160   /**
    161    * Current offset for the upload.
    162    */
    163   size_t upload_off;
    164 
    165   /**
    166    * HTTP response code to use on resume, if resp is set.
    167    */
    168   unsigned int response_code;
    169 
    170   /**
    171    * For how many years does the client still have
    172    * to pay?
    173    */
    174   unsigned int years_to_pay;
    175 
    176   /**
    177    * true if client provided a payment secret / order ID?
    178    */
    179   bool payment_identifier_provided;
    180 
    181 };
    182 
    183 
    184 /**
    185  * Kept in DLL for shutdown handling while suspended.
    186  */
    187 static struct PolicyUploadContext *puc_head;
    188 
    189 /**
    190  * Kept in DLL for shutdown handling while suspended.
    191  */
    192 static struct PolicyUploadContext *puc_tail;
    193 
    194 
    195 /**
    196  * Service is shutting down, resume all MHD connections NOW.
    197  */
    198 void
    199 AH_resume_all_bc ()
    200 {
    201   struct PolicyUploadContext *puc;
    202 
    203   while (NULL != (puc = puc_head))
    204   {
    205     GNUNET_CONTAINER_DLL_remove (puc_head,
    206                                  puc_tail,
    207                                  puc);
    208     if (NULL != puc->po)
    209     {
    210       TALER_MERCHANT_post_private_orders_cancel (puc->po);
    211       puc->po = NULL;
    212     }
    213     if (NULL != puc->cpo)
    214     {
    215       TALER_MERCHANT_get_private_order_cancel (puc->cpo);
    216       puc->cpo = NULL;
    217     }
    218     MHD_resume_connection (puc->con);
    219   }
    220 }
    221 
    222 
    223 /**
    224  * Function called to clean up a backup context.
    225  *
    226  * @param hc a `struct PolicyUploadContext`
    227  */
    228 static void
    229 cleanup_ctx (struct TM_HandlerContext *hc)
    230 {
    231   struct PolicyUploadContext *puc = hc->ctx;
    232 
    233   if (NULL != puc->po)
    234     TALER_MERCHANT_post_private_orders_cancel (puc->po);
    235   if (NULL != puc->cpo)
    236     TALER_MERCHANT_get_private_order_cancel (puc->cpo);
    237   if (NULL != puc->hash_ctx)
    238     GNUNET_CRYPTO_hash_context_abort (puc->hash_ctx);
    239   if (NULL != puc->resp)
    240     MHD_destroy_response (puc->resp);
    241   GNUNET_free (puc->upload);
    242   GNUNET_free (puc->meta_data);
    243   GNUNET_free (puc);
    244 }
    245 
    246 
    247 /**
    248  * Transmit a payment request for @a order_id on @a connection
    249  *
    250  * @param[in,out] puc details about the operation
    251  * @return #GNUNET_OK on success
    252  */
    253 static int
    254 make_payment_request (struct PolicyUploadContext *puc)
    255 {
    256   struct MHD_Response *resp;
    257 
    258   /* request payment via Taler */
    259   resp = MHD_create_response_from_buffer (0,
    260                                           NULL,
    261                                           MHD_RESPMEM_PERSISTENT);
    262   if (NULL == resp)
    263   {
    264     GNUNET_break (0);
    265     return GNUNET_SYSERR;
    266   }
    267   TALER_MHD_add_global_headers (resp,
    268                                 false);
    269   {
    270     char *hdr;
    271     const char *pfx;
    272     char *hn;
    273 
    274     if (0 == strncasecmp ("https://",
    275                           AH_backend_url,
    276                           strlen ("https://")))
    277     {
    278       pfx = "taler://";
    279       hn = &AH_backend_url[strlen ("https://")];
    280     }
    281     else if (0 == strncasecmp ("http://",
    282                                AH_backend_url,
    283                                strlen ("http://")))
    284     {
    285       pfx = "taler+http://";
    286       hn = &AH_backend_url[strlen ("http://")];
    287     }
    288     else
    289     {
    290       GNUNET_break (0);
    291       MHD_destroy_response (resp);
    292       return GNUNET_SYSERR;
    293     }
    294     if (0 == strlen (hn))
    295     {
    296       GNUNET_break (0);
    297       MHD_destroy_response (resp);
    298       return GNUNET_SYSERR;
    299     }
    300     {
    301       char *order_id;
    302 
    303       order_id = GNUNET_STRINGS_data_to_string_alloc (
    304         &puc->payment_identifier,
    305         sizeof (puc->payment_identifier));
    306       GNUNET_asprintf (&hdr,
    307                        "%spay/%s%s/",
    308                        pfx,
    309                        hn,
    310                        order_id);
    311       GNUNET_free (order_id);
    312     }
    313     GNUNET_break (MHD_YES ==
    314                   MHD_add_response_header (resp,
    315                                            ANASTASIS_HTTP_HEADER_TALER,
    316                                            hdr));
    317     GNUNET_free (hdr);
    318   }
    319   puc->resp = resp;
    320   puc->response_code = MHD_HTTP_PAYMENT_REQUIRED;
    321   return GNUNET_OK;
    322 }
    323 
    324 
    325 /**
    326  * Callbacks of this type are used to serve the result of submitting a
    327  * POST /private/orders request to a merchant.
    328  *
    329  * @param cls our `struct PolicyUploadContext`
    330  * @param por response details
    331  */
    332 static void
    333 proposal_cb (struct PolicyUploadContext *puc,
    334              const struct TALER_MERCHANT_PostPrivateOrdersResponse *por)
    335 {
    336   enum GNUNET_DB_QueryStatus qs;
    337 
    338   puc->po = NULL;
    339   GNUNET_CONTAINER_DLL_remove (puc_head,
    340                                puc_tail,
    341                                puc);
    342   MHD_resume_connection (puc->con);
    343   AH_trigger_daemon (NULL);
    344   if (MHD_HTTP_OK != por->hr.http_status)
    345   {
    346     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    347                 "Backend returned status %u/%d when trying to setup order\n",
    348                 por->hr.http_status,
    349                 (int) por->hr.ec);
    350     puc->resp = TALER_MHD_MAKE_JSON_PACK (
    351       GNUNET_JSON_pack_uint64 ("code",
    352                                TALER_EC_SYNC_PAYMENT_CREATE_BACKEND_ERROR),
    353       GNUNET_JSON_pack_string ("hint",
    354                                "Failed to setup order with merchant backend"),
    355       GNUNET_JSON_pack_uint64 ("backend-ec",
    356                                por->hr.ec),
    357       GNUNET_JSON_pack_uint64 ("backend-http-status",
    358                                por->hr.http_status),
    359       GNUNET_JSON_pack_allow_null (
    360         GNUNET_JSON_pack_object_incref ("backend-reply",
    361                                         (json_t *) por->hr.reply)));
    362     puc->response_code = MHD_HTTP_BAD_GATEWAY;
    363     return;
    364   }
    365   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    366               "Storing payment request for order `%s'\n",
    367               por->details.ok.order_id);
    368 
    369   qs = ANASTASIS_DB_do_insert_recdoc_payment (
    370     &puc->account,
    371     (uint32_t) AH_post_counter,
    372     &puc->payment_identifier,
    373     &AH_annual_fee);
    374   if (0 >= qs)
    375   {
    376     GNUNET_break (0);
    377     puc->resp = TALER_MHD_make_error (
    378       TALER_EC_GENERIC_DB_STORE_FAILED,
    379       "insert recdoc payment");
    380     puc->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
    381     return;
    382   }
    383   if (GNUNET_OK !=
    384       make_payment_request (puc))
    385   {
    386     GNUNET_break (0);
    387     puc->resp = TALER_MHD_make_error (
    388       TALER_EC_GENERIC_DB_STORE_FAILED,
    389       "failed to initiate payment");
    390     puc->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
    391   }
    392 }
    393 
    394 
    395 /**
    396  * Callback to process a GET /check-payment request
    397  *
    398  * @param cls our `struct PolicyUploadContext`
    399  * @param osr order status
    400  */
    401 static void
    402 check_payment_cb (struct PolicyUploadContext *puc,
    403                   const struct TALER_MERCHANT_GetPrivateOrderResponse *osr)
    404 {
    405   const struct TALER_MERCHANT_HttpResponse *hr = &osr->hr;
    406 
    407   /* refunds are not supported, verify */
    408   puc->cpo = NULL;
    409   GNUNET_CONTAINER_DLL_remove (puc_head,
    410                                puc_tail,
    411                                puc);
    412   MHD_resume_connection (puc->con);
    413   AH_trigger_daemon (NULL);
    414   switch (hr->http_status)
    415   {
    416   case MHD_HTTP_OK:
    417     GNUNET_assert (NULL != osr);
    418     break; /* processed below */
    419   case MHD_HTTP_UNAUTHORIZED:
    420     puc->resp = TALER_MHD_make_error (
    421       TALER_EC_ANASTASIS_GENERIC_PAYMENT_CHECK_UNAUTHORIZED,
    422       NULL);
    423     puc->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
    424     return;
    425   default:
    426     puc->resp = TALER_MHD_make_error (
    427       TALER_EC_ANASTASIS_GENERIC_BACKEND_ERROR,
    428       "failed to initiate payment");
    429     puc->response_code = MHD_HTTP_BAD_GATEWAY;
    430     return;
    431   }
    432 
    433   GNUNET_assert (MHD_HTTP_OK == hr->http_status);
    434   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    435               "Payment status checked: %d\n",
    436               osr->details.ok.status);
    437   switch (osr->details.ok.status)
    438   {
    439   case TALER_MERCHANT_OSC_PAID:
    440     {
    441       enum GNUNET_DB_QueryStatus qs;
    442       unsigned int years;
    443       struct GNUNET_TIME_Relative paid_until;
    444       const json_t *contract;
    445       struct TALER_Amount amount;
    446       struct GNUNET_JSON_Specification cspec[] = {
    447         TALER_JSON_spec_amount_any ("amount",
    448                                     &amount),
    449         GNUNET_JSON_spec_end ()
    450       };
    451 
    452       contract = osr->details.ok.details.paid.contract_terms;
    453       if (GNUNET_OK !=
    454           GNUNET_JSON_parse (contract,
    455                              cspec,
    456                              NULL, NULL))
    457       {
    458         GNUNET_break (0);
    459         puc->resp = TALER_MHD_make_error (
    460           TALER_EC_MERCHANT_GENERIC_DB_CONTRACT_CONTENT_INVALID,
    461           "no amount given");
    462         puc->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
    463         return; /* continue as planned */
    464       }
    465       years = TALER_amount_divide2 (&amount,
    466                                     &AH_annual_fee);
    467       paid_until = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_YEARS,
    468                                                   years);
    469       /* add 1 week grace period, otherwise if a user
    470          wants to pay for 1 year, the first seconds
    471          would have passed between making the payment
    472          and our subsequent check if +1 year was
    473          paid... So we actually say 1 year = 52 weeks
    474          on the server, while the client calculates
    475          with 365 days. */
    476       paid_until = GNUNET_TIME_relative_add (paid_until,
    477                                              GNUNET_TIME_UNIT_WEEKS);
    478 
    479       qs = ANASTASIS_DB_do_update_account_lifetime (
    480         &puc->account,
    481         &puc->payment_identifier,
    482         GNUNET_TIME_timestamp_get (),
    483         paid_until,
    484         &puc->paid_until);
    485       if (0 <= qs)
    486         return; /* continue as planned */
    487       GNUNET_break (0);
    488       puc->resp = TALER_MHD_make_error (
    489         TALER_EC_GENERIC_DB_FETCH_FAILED,
    490         "do update account lifetime");
    491       puc->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
    492       return; /* continue as planned */
    493     }
    494   case TALER_MERCHANT_OSC_UNPAID:
    495   case TALER_MERCHANT_OSC_CLAIMED:
    496     break;
    497   }
    498   if (! GNUNET_TIME_absolute_is_zero (puc->existing_pi_timestamp.abs_time))
    499   {
    500     /* repeat payment request */
    501     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    502                 "Repeating payment request\n");
    503     if (GNUNET_OK !=
    504         make_payment_request (puc))
    505     {
    506       GNUNET_break (0);
    507       puc->resp = TALER_MHD_make_error (
    508         TALER_EC_GENERIC_DB_STORE_FAILED,
    509         "failed to initiate payment");
    510       puc->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
    511     }
    512     return;
    513   }
    514   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    515               "Timeout waiting for payment\n");
    516   puc->resp = TALER_MHD_make_error (TALER_EC_SYNC_PAYMENT_GENERIC_TIMEOUT,
    517                                     "Timeout awaiting promised payment");
    518   GNUNET_assert (NULL != puc->resp);
    519   puc->response_code = MHD_HTTP_REQUEST_TIMEOUT;
    520 }
    521 
    522 
    523 /**
    524  * Helper function used to ask our backend to await
    525  * a payment for the user's account.
    526  *
    527  * @param puc context to begin payment for.
    528  */
    529 static void
    530 await_payment (struct PolicyUploadContext *puc)
    531 {
    532   struct GNUNET_TIME_Relative timeout
    533     = GNUNET_TIME_absolute_get_remaining (puc->timeout);
    534 
    535   GNUNET_CONTAINER_DLL_insert (puc_head,
    536                                puc_tail,
    537                                puc);
    538   MHD_suspend_connection (puc->con);
    539   {
    540     char *order_id;
    541 
    542     order_id = GNUNET_STRINGS_data_to_string_alloc (
    543       &puc->payment_identifier,
    544       sizeof(struct ANASTASIS_PaymentSecretP));
    545     puc->cpo = TALER_MERCHANT_get_private_order_create (AH_ctx,
    546                                                         AH_backend_url,
    547                                                         order_id);
    548     GNUNET_assert (NULL != puc->cpo);
    549     GNUNET_free (order_id);
    550     GNUNET_assert (
    551       GNUNET_OK ==
    552       TALER_MERCHANT_get_private_order_set_options (
    553         puc->cpo,
    554         TALER_MERCHANT_get_private_order_option_timeout (timeout)));
    555     GNUNET_assert (
    556       TALER_EC_NONE ==
    557       TALER_MERCHANT_get_private_order_start (puc->cpo,
    558                                               &check_payment_cb,
    559                                               puc));
    560   }
    561   AH_trigger_curl ();
    562 }
    563 
    564 
    565 /**
    566  * Helper function used to ask our backend to begin processing a
    567  * payment for the user's account.  May perform asynchronous
    568  * operations by suspending the connection if required.
    569  *
    570  * @param puc context to begin payment for.
    571  * @return MHD status code
    572  */
    573 static enum MHD_Result
    574 begin_payment (struct PolicyUploadContext *puc)
    575 {
    576   json_t *order;
    577 
    578   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    579               "Suspending connection while creating order at `%s'\n",
    580               AH_backend_url);
    581   {
    582     char *order_id;
    583     struct TALER_Amount upload_fee;
    584 
    585     if (0 >
    586         TALER_amount_multiply (&upload_fee,
    587                                &AH_annual_fee,
    588                                puc->years_to_pay))
    589     {
    590       GNUNET_break_op (0);
    591       return TALER_MHD_reply_with_error (puc->con,
    592                                          MHD_HTTP_BAD_REQUEST,
    593                                          TALER_EC_GENERIC_PARAMETER_MALFORMED,
    594                                          "storage_duration_years");
    595     }
    596 
    597     order_id = GNUNET_STRINGS_data_to_string_alloc (
    598       &puc->payment_identifier,
    599       sizeof(struct ANASTASIS_PaymentSecretP));
    600     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    601                 "Creating order for %u years with payment of %s\n",
    602                 puc->years_to_pay,
    603                 TALER_amount2s (&upload_fee));
    604     order = json_pack ("{s:o, s:s, s:[{s:s,s:I,s:s}], s:s }",
    605                        "amount", TALER_JSON_from_amount (&upload_fee),
    606                        "summary", "Anastasis policy storage fee",
    607                        "products",
    608                        "description", "policy storage fee",
    609                        "quantity", (json_int_t) puc->years_to_pay,
    610                        "unit", "years",
    611                        "order_id", order_id);
    612     GNUNET_free (order_id);
    613     if (NULL == order)
    614     {
    615       GNUNET_break (0);
    616       return TALER_MHD_reply_with_error (puc->con,
    617                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
    618                                          TALER_EC_GENERIC_JSON_ALLOCATION_FAILURE,
    619                                          "could not create order");
    620     }
    621   }
    622   /* Only link into the list once we are actually about to suspend: the list
    623      exists to resume suspended connections at shutdown, and cleanup_ctx()
    624      frees the context without unlinking it, so an error return above would
    625      otherwise leave a dangling entry behind. */
    626   GNUNET_CONTAINER_DLL_insert (puc_head,
    627                                puc_tail,
    628                                puc);
    629   MHD_suspend_connection (puc->con);
    630   puc->po = TALER_MERCHANT_post_private_orders_create (AH_ctx,
    631                                                        AH_backend_url,
    632                                                        order);
    633   GNUNET_assert (NULL != puc->po);
    634   GNUNET_assert (
    635     GNUNET_OK ==
    636     TALER_MERCHANT_post_private_orders_set_options (
    637       puc->po,
    638       TALER_MERCHANT_post_private_orders_option_create_token (false)));
    639   GNUNET_assert (TALER_EC_NONE ==
    640                  TALER_MERCHANT_post_private_orders_start (puc->po,
    641                                                            &proposal_cb,
    642                                                            puc));
    643   AH_trigger_curl ();
    644   json_decref (order);
    645   return MHD_YES;
    646 }
    647 
    648 
    649 /**
    650  * Prepare to receive a payment, possibly requesting it, or just waiting
    651  * for it to be completed by the client.
    652  *
    653  * @param puc context to prepare payment for
    654  * @return MHD status
    655  */
    656 static enum MHD_Result
    657 prepare_payment (struct PolicyUploadContext *puc)
    658 {
    659   if (! puc->payment_identifier_provided)
    660   {
    661     GNUNET_CRYPTO_random_block (
    662       &puc->payment_identifier,
    663       sizeof (struct ANASTASIS_PaymentSecretP));
    664     puc->payment_identifier_provided = true;
    665     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    666                 "No payment identifier, initiating payment\n");
    667     return begin_payment (puc);
    668   }
    669   await_payment (puc);
    670   return MHD_YES;
    671 }
    672 
    673 
    674 enum MHD_Result
    675 AH_handler_policy_post (
    676   struct MHD_Connection *connection,
    677   struct TM_HandlerContext *hc,
    678   const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub,
    679   const char *recovery_data,
    680   size_t *recovery_data_size)
    681 {
    682   struct PolicyUploadContext *puc = hc->ctx;
    683 
    684   if (NULL == puc)
    685   {
    686     /* first call, setup internals */
    687     puc = GNUNET_new (struct PolicyUploadContext);
    688     hc->ctx = puc;
    689     hc->cc = &cleanup_ctx;
    690     puc->con = connection;
    691 
    692     TALER_MHD_parse_request_header_auto (connection,
    693                                          ANASTASIS_HTTP_HEADER_PAYMENT_IDENTIFIER,
    694                                          &puc->payment_identifier,
    695                                          puc->payment_identifier_provided);
    696     puc->account = *account_pub;
    697 
    698     /* check for meta-data */
    699     {
    700       const char *metas;
    701 
    702       metas = MHD_lookup_connection_value (connection,
    703                                            MHD_HEADER_KIND,
    704                                            ANASTASIS_HTTP_HEADER_POLICY_META_DATA);
    705       if (NULL == metas)
    706       {
    707         GNUNET_break_op (0);
    708         return TALER_MHD_reply_with_error (
    709           connection,
    710           MHD_HTTP_BAD_REQUEST,
    711           TALER_EC_GENERIC_HTTP_HEADERS_MALFORMED,
    712           ANASTASIS_HTTP_HEADER_POLICY_META_DATA
    713           " header must be present");
    714       }
    715       if (GNUNET_OK !=
    716           GNUNET_STRINGS_string_to_data_alloc (metas,
    717                                                strlen (metas),
    718                                                &puc->meta_data,
    719                                                &puc->meta_data_size))
    720       {
    721         GNUNET_break_op (0);
    722         return TALER_MHD_reply_with_error (
    723           connection,
    724           MHD_HTTP_BAD_REQUEST,
    725           TALER_EC_GENERIC_HTTP_HEADERS_MALFORMED,
    726           ANASTASIS_HTTP_HEADER_POLICY_META_DATA
    727           " header must include a base32-encoded value");
    728       }
    729     }
    730     TALER_MHD_parse_request_header_auto_t (connection,
    731                                            ANASTASIS_HTTP_HEADER_POLICY_SIGNATURE,
    732                                            &puc->account_sig);
    733     {
    734       /* Check if header contains an ETAG */
    735       const char *etag;
    736 
    737       etag = MHD_lookup_connection_value (connection,
    738                                           MHD_HEADER_KIND,
    739                                           MHD_HTTP_HEADER_IF_NONE_MATCH);
    740       if ( (NULL == etag) ||
    741            (2 >= strlen (etag)) ||
    742            ('"' != etag[0]) ||
    743            ('"' != etag[strlen (etag) - 1]) ||
    744            (GNUNET_OK !=
    745             GNUNET_STRINGS_string_to_data (etag + 1,
    746                                            strlen (etag) - 2,
    747                                            &puc->new_policy_upload_hash,
    748                                            sizeof (puc->new_policy_upload_hash))
    749            ) )
    750       {
    751         GNUNET_break_op (0);
    752         return TALER_MHD_reply_with_error (connection,
    753                                            MHD_HTTP_BAD_REQUEST,
    754                                            TALER_EC_ANASTASIS_POLICY_BAD_IF_MATCH,
    755                                            MHD_HTTP_HEADER_IF_NONE_MATCH
    756                                            " header must include a base32-encoded SHA-512 hash");
    757       }
    758     }
    759     /* validate signature */
    760     {
    761       struct ANASTASIS_UploadSignaturePS usp = {
    762         .purpose.size = htonl (sizeof (usp)),
    763         .purpose.purpose = htonl (TALER_SIGNATURE_ANASTASIS_POLICY_UPLOAD),
    764         .new_recovery_data_hash = puc->new_policy_upload_hash
    765       };
    766 
    767       if (GNUNET_OK !=
    768           GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_ANASTASIS_POLICY_UPLOAD,
    769                                       &usp,
    770                                       &puc->account_sig.eddsa_sig,
    771                                       &account_pub->pub))
    772       {
    773         GNUNET_break_op (0);
    774         return TALER_MHD_reply_with_error (connection,
    775                                            MHD_HTTP_FORBIDDEN,
    776                                            TALER_EC_ANASTASIS_POLICY_BAD_SIGNATURE,
    777                                            ANASTASIS_HTTP_HEADER_POLICY_SIGNATURE);
    778       }
    779     }
    780 
    781     /* Only now, with the account signature verified, do we allocate the
    782        upload buffer: sizing it from the client-declared Content-Length before
    783        checking who is asking lets anyone force repeated multi-megabyte
    784        allocations. */
    785     /* now setup 'puc' */
    786     {
    787       const char *lens;
    788       unsigned long len;
    789       char dummy;
    790 
    791       lens = MHD_lookup_connection_value (connection,
    792                                           MHD_HEADER_KIND,
    793                                           MHD_HTTP_HEADER_CONTENT_LENGTH);
    794       if ( (NULL == lens) ||
    795            (1 != sscanf (lens,
    796                          "%lu%c",
    797                          &len,
    798                          &dummy)) )
    799       {
    800         GNUNET_break_op (0);
    801         return TALER_MHD_reply_with_error (
    802           connection,
    803           MHD_HTTP_BAD_REQUEST,
    804           (NULL == lens)
    805           ? TALER_EC_ANASTASIS_GENERIC_MISSING_CONTENT_LENGTH
    806           : TALER_EC_ANASTASIS_GENERIC_MALFORMED_CONTENT_LENGTH,
    807           NULL);
    808       }
    809       if (len / 1024 / 1024 >= AH_upload_limit_mb)
    810       {
    811         GNUNET_break_op (0);
    812         return TALER_MHD_reply_with_error (connection,
    813                                            MHD_HTTP_PAYLOAD_TOO_LARGE,
    814                                            TALER_EC_SYNC_MALFORMED_CONTENT_LENGTH,
    815                                            "Content-length value not acceptable");
    816       }
    817       puc->upload = GNUNET_malloc_large (len);
    818       if (NULL == puc->upload)
    819       {
    820         GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
    821                              "malloc");
    822         return TALER_MHD_reply_with_error (connection,
    823                                            MHD_HTTP_PAYLOAD_TOO_LARGE,
    824                                            TALER_EC_ANASTASIS_POLICY_OUT_OF_MEMORY_ON_CONTENT_LENGTH,
    825                                            NULL);
    826       }
    827       puc->upload_size = (size_t) len;
    828     }
    829 
    830     puc->timeout = GNUNET_TIME_relative_to_absolute (
    831       CHECK_PAYMENT_GENERIC_TIMEOUT);
    832     TALER_MHD_parse_request_timeout (connection,
    833                                      &puc->timeout);
    834 
    835     /* check if the client insists on paying */
    836     {
    837       const char *req;
    838       unsigned int years;
    839 
    840       req = MHD_lookup_connection_value (connection,
    841                                          MHD_GET_ARGUMENT_KIND,
    842                                          "storage_duration");
    843       if (NULL != req)
    844       {
    845         char dummy;
    846 
    847         if (1 != sscanf (req,
    848                          "%u%c",
    849                          &years,
    850                          &dummy))
    851         {
    852           GNUNET_break_op (0);
    853           return TALER_MHD_reply_with_error (connection,
    854                                              MHD_HTTP_BAD_REQUEST,
    855                                              TALER_EC_GENERIC_PARAMETER_MALFORMED,
    856                                              "storage_duration (must be non-negative number)");
    857         }
    858         if (years > ANASTASIS_MAX_YEARS_STORAGE)
    859         {
    860           GNUNET_break_op (0);
    861           return TALER_MHD_reply_with_error (
    862             connection,
    863             MHD_HTTP_BAD_REQUEST,
    864             TALER_EC_GENERIC_PARAMETER_MALFORMED,
    865             "storage_duration (exceeds maximum storage duration)");
    866         }
    867       }
    868       else
    869       {
    870         years = 1;
    871       }
    872       puc->end_date = GNUNET_TIME_relative_to_timestamp (
    873         GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_YEARS,
    874                                        years));
    875     }
    876 
    877     /* get ready to hash (done here as we may go async for payments next) */
    878     puc->hash_ctx = GNUNET_CRYPTO_hash_context_start ();
    879 
    880     /* Check database to see if the transaction is permissible */
    881     {
    882       struct GNUNET_TIME_Relative rem;
    883 
    884       rem = GNUNET_TIME_absolute_get_remaining (puc->end_date.abs_time);
    885       puc->years_to_pay = rem.rel_value_us
    886                           / GNUNET_TIME_UNIT_YEARS.rel_value_us;
    887       if (0 != (rem.rel_value_us % GNUNET_TIME_UNIT_YEARS.rel_value_us))
    888         puc->years_to_pay++;
    889       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    890                   "Calculated years to pay to be %u until %s\n",
    891                   puc->years_to_pay,
    892                   GNUNET_TIME_absolute2s (puc->end_date.abs_time));
    893 
    894       if (puc->payment_identifier_provided)
    895       {
    896         /* check if payment identifier is valid (existing and paid) */
    897         bool paid = false;
    898         bool valid_counter = false;
    899         enum GNUNET_DB_QueryStatus qs;
    900 
    901         qs = ANASTASIS_DB_get_recdoc_payment (
    902           &puc->payment_identifier,
    903           &paid,
    904           &valid_counter,
    905           &puc->existing_pi_timestamp);
    906         if (qs < 0)
    907           return TALER_MHD_reply_with_error (puc->con,
    908                                              MHD_HTTP_INTERNAL_SERVER_ERROR,
    909                                              TALER_EC_GENERIC_DB_FETCH_FAILED,
    910                                              NULL);
    911         if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
    912         {
    913           /* The client named a payment identifier we have no record of.  The
    914              result specification was not touched in that case, so we must not
    915              look at @e paid or @e valid_counter; treat it as unpaid. */
    916           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    917                       "Given payment identifier is unknown, initiating payment\n");
    918           puc->payment_identifier_provided = false;
    919           if (0 == puc->years_to_pay)
    920             puc->years_to_pay = 1;
    921           return prepare_payment (puc);
    922         }
    923 
    924         if ( (! paid) ||
    925              (! valid_counter) )
    926         {
    927           if (! valid_counter)
    928           {
    929             puc->payment_identifier_provided = false;
    930             if (0 == puc->years_to_pay)
    931               puc->years_to_pay = 1;
    932             GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    933                         "Too many uploads with this payment identifier, initiating fresh payment\n")
    934             ;
    935           }
    936           else
    937           {
    938             GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    939                         "Given payment identifier not known to be paid, initiating payment\n");
    940           }
    941           return prepare_payment (puc);
    942         }
    943       }
    944 
    945       if (! puc->payment_identifier_provided)
    946       {
    947         enum GNUNET_DB_QueryStatus qs;
    948         struct GNUNET_TIME_Relative rel;
    949 
    950         /* generate fresh payment identifier */
    951         GNUNET_CRYPTO_random_block (&puc->payment_identifier,
    952                                     sizeof (struct ANASTASIS_PaymentSecretP));
    953         if (! TALER_amount_is_zero (&AH_annual_fee))
    954         {
    955           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    956                       "No payment identifier, requesting payment\n");
    957           return begin_payment (puc);
    958         }
    959         /* Cost is zero, fake "zero" payment having happened */
    960         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    961                     "Policy upload is free, allowing upload without payment\n");
    962         qs = ANASTASIS_DB_do_insert_recdoc_payment (
    963           account_pub,
    964           AH_post_counter,
    965           &puc->payment_identifier,
    966           &AH_annual_fee);
    967         if (qs <= 0)
    968           return TALER_MHD_reply_with_error (puc->con,
    969                                              MHD_HTTP_INTERNAL_SERVER_ERROR,
    970                                              TALER_EC_GENERIC_DB_FETCH_FAILED,
    971                                              NULL);
    972         rel = GNUNET_TIME_relative_multiply (
    973           GNUNET_TIME_UNIT_YEARS,
    974           ANASTASIS_MAX_YEARS_STORAGE);
    975         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    976                     "Policy lifetime is %s (%u years)\n",
    977                     GNUNET_TIME_relative2s (rel,
    978                                             true),
    979                     ANASTASIS_MAX_YEARS_STORAGE);
    980         qs = ANASTASIS_DB_do_update_account_lifetime (
    981           account_pub,
    982           &puc->payment_identifier,
    983           GNUNET_TIME_relative_to_timestamp (rel),
    984           GNUNET_TIME_UNIT_ZERO,
    985           &puc->paid_until);
    986         if (qs <= 0)
    987         {
    988           GNUNET_break (0);
    989           return TALER_MHD_reply_with_error (puc->con,
    990                                              MHD_HTTP_INTERNAL_SERVER_ERROR,
    991                                              TALER_EC_GENERIC_DB_FETCH_FAILED,
    992                                              NULL);
    993         }
    994       }
    995     }
    996 
    997     /* Check if existing policy matches upload (and if, skip it) */
    998     {
    999       struct GNUNET_HashCode hash;
   1000       enum ANASTASIS_DB_AccountStatus as;
   1001       uint32_t version;
   1002       struct GNUNET_TIME_Timestamp now;
   1003       struct GNUNET_TIME_Relative rem;
   1004 
   1005       as = ANASTASIS_DB_get_account (
   1006         account_pub,
   1007         &puc->paid_until,
   1008         &hash,
   1009         &version);
   1010       now = GNUNET_TIME_timestamp_get ();
   1011       if (GNUNET_TIME_timestamp_cmp (puc->paid_until,
   1012                                      <,
   1013                                      now))
   1014         puc->paid_until = now;
   1015       rem = GNUNET_TIME_absolute_get_difference (puc->paid_until.abs_time,
   1016                                                  puc->end_date.abs_time);
   1017       puc->years_to_pay = rem.rel_value_us
   1018                           / GNUNET_TIME_UNIT_YEARS.rel_value_us;
   1019       if (0 != (rem.rel_value_us % GNUNET_TIME_UNIT_YEARS.rel_value_us))
   1020         puc->years_to_pay++;
   1021       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1022                   "Calculated years to pay to be %u until %s\n",
   1023                   puc->years_to_pay,
   1024                   GNUNET_TIME_absolute2s (puc->end_date.abs_time));
   1025       if ( (ANASTASIS_DB_ACCOUNT_STATUS_VALID_HASH_RETURNED == as) &&
   1026            (0 != puc->years_to_pay) )
   1027       {
   1028         /* user requested extension, force payment */
   1029         as = ANASTASIS_DB_ACCOUNT_STATUS_PAYMENT_REQUIRED;
   1030       }
   1031       switch (as)
   1032       {
   1033       case ANASTASIS_DB_ACCOUNT_STATUS_PAYMENT_REQUIRED:
   1034         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1035                     "Expiration too low, initiating payment\n");
   1036         return prepare_payment (puc);
   1037       case ANASTASIS_DB_ACCOUNT_STATUS_HARD_ERROR:
   1038         return TALER_MHD_reply_with_error (puc->con,
   1039                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
   1040                                            TALER_EC_GENERIC_DB_FETCH_FAILED,
   1041                                            NULL);
   1042       case ANASTASIS_DB_ACCOUNT_STATUS_NO_RESULTS:
   1043         /* continue below */
   1044         break;
   1045       case ANASTASIS_DB_ACCOUNT_STATUS_VALID_HASH_RETURNED:
   1046         if (0 == GNUNET_memcmp (&hash,
   1047                                 &puc->new_policy_upload_hash))
   1048         {
   1049           /* Refuse upload: we already have that backup! */
   1050           struct MHD_Response *resp;
   1051           enum MHD_Result ret;
   1052           char version_s[14];
   1053 
   1054           GNUNET_snprintf (version_s,
   1055                            sizeof (version_s),
   1056                            "%u",
   1057                            (unsigned int) version);
   1058           resp = MHD_create_response_from_buffer (0,
   1059                                                   NULL,
   1060                                                   MHD_RESPMEM_PERSISTENT);
   1061           TALER_MHD_add_global_headers (resp,
   1062                                         false);
   1063           GNUNET_break (MHD_YES ==
   1064                         MHD_add_response_header (resp,
   1065                                                  ANASTASIS_HTTP_HEADER_POLICY_VERSION,
   1066                                                  version_s));
   1067           ret = MHD_queue_response (connection,
   1068                                     MHD_HTTP_NOT_MODIFIED,
   1069                                     resp);
   1070           GNUNET_break (MHD_YES == ret);
   1071           MHD_destroy_response (resp);
   1072           return ret;
   1073         }
   1074         break;
   1075       }
   1076     }
   1077     /* ready to begin! */
   1078     return MHD_YES;
   1079   }
   1080 
   1081   if (NULL != puc->resp)
   1082   {
   1083     enum MHD_Result ret;
   1084 
   1085     /* We generated a response asynchronously, queue that */
   1086     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1087                 "Returning asynchronously generated response with HTTP status %u\n",
   1088                 puc->response_code);
   1089     ret = MHD_queue_response (connection,
   1090                               puc->response_code,
   1091                               puc->resp);
   1092     GNUNET_break (MHD_YES == ret);
   1093     MHD_destroy_response (puc->resp);
   1094     puc->resp = NULL;
   1095     return ret;
   1096   }
   1097 
   1098   /* handle upload */
   1099   if (0 != *recovery_data_size)
   1100   {
   1101     /* check MHD invariant */
   1102     GNUNET_assert (puc->upload_off + *recovery_data_size <= puc->upload_size);
   1103     memcpy (&puc->upload[puc->upload_off],
   1104             recovery_data,
   1105             *recovery_data_size);
   1106     puc->upload_off += *recovery_data_size;
   1107     GNUNET_CRYPTO_hash_context_read (puc->hash_ctx,
   1108                                      recovery_data,
   1109                                      *recovery_data_size);
   1110     *recovery_data_size = 0;
   1111     return MHD_YES;
   1112   }
   1113 
   1114   if ( (0 == puc->upload_off) &&
   1115        (0 != puc->upload_size) &&
   1116        (NULL == puc->resp) )
   1117   {
   1118     /* wait for upload */
   1119     return MHD_YES;
   1120   }
   1121 
   1122   /* finished with upload, check hash */
   1123   if (NULL != puc->hash_ctx)
   1124   {
   1125     struct GNUNET_HashCode our_hash;
   1126 
   1127     GNUNET_CRYPTO_hash_context_finish (puc->hash_ctx,
   1128                                        &our_hash);
   1129     puc->hash_ctx = NULL;
   1130     if (0 != GNUNET_memcmp (&our_hash,
   1131                             &puc->new_policy_upload_hash))
   1132     {
   1133       GNUNET_break_op (0);
   1134       return TALER_MHD_reply_with_error (connection,
   1135                                          MHD_HTTP_BAD_REQUEST,
   1136                                          TALER_EC_ANASTASIS_POLICY_INVALID_UPLOAD,
   1137                                          "Data uploaded does not match Etag promise");
   1138     }
   1139   }
   1140 
   1141   /* store backup to database */
   1142   {
   1143     enum ANASTASIS_DB_StoreStatus ss;
   1144     uint32_t version = UINT32_MAX;
   1145     char version_s[14];
   1146     char expir_s[32];
   1147 
   1148     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1149                 "Uploading recovery document\n");
   1150     ss = ANASTASIS_DB_do_insert_recovery_document (
   1151       &puc->account,
   1152       &puc->account_sig,
   1153       &puc->new_policy_upload_hash,
   1154       puc->upload,
   1155       puc->upload_size,
   1156       puc->meta_data,
   1157       puc->meta_data_size,
   1158       &puc->payment_identifier,
   1159       &version);
   1160     GNUNET_snprintf (version_s,
   1161                      sizeof (version_s),
   1162                      "%u",
   1163                      (unsigned int) version);
   1164     GNUNET_snprintf (expir_s,
   1165                      sizeof (expir_s),
   1166                      "%llu",
   1167                      (unsigned long long)
   1168                      (puc->paid_until.abs_time.abs_value_us
   1169                       / GNUNET_TIME_UNIT_SECONDS.rel_value_us));
   1170     switch (ss)
   1171     {
   1172     case ANASTASIS_DB_STORE_STATUS_STORE_LIMIT_EXCEEDED:
   1173       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1174                   "Storage request limit exceeded, requesting payment\n");
   1175       if (! puc->payment_identifier_provided)
   1176       {
   1177         GNUNET_CRYPTO_random_block (&puc->payment_identifier,
   1178                                     sizeof (struct ANASTASIS_PaymentSecretP));
   1179         puc->payment_identifier_provided = true;
   1180         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1181                     "Also no payment identifier, requesting payment\n");
   1182       }
   1183       return begin_payment (puc);
   1184     case ANASTASIS_DB_STORE_STATUS_PAYMENT_REQUIRED:
   1185       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1186                   "Policy store operation requires payment\n");
   1187       if (! puc->payment_identifier_provided)
   1188       {
   1189         GNUNET_CRYPTO_random_block (&puc->payment_identifier,
   1190                                     sizeof (struct ANASTASIS_PaymentSecretP));
   1191         puc->payment_identifier_provided = true;
   1192       }
   1193       return begin_payment (puc);
   1194     case ANASTASIS_DB_STORE_STATUS_HARD_ERROR:
   1195     case ANASTASIS_DB_STORE_STATUS_SOFT_ERROR:
   1196       return TALER_MHD_reply_with_error (puc->con,
   1197                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
   1198                                          TALER_EC_GENERIC_DB_FETCH_FAILED,
   1199                                          NULL);
   1200     case ANASTASIS_DB_STORE_STATUS_NO_RESULTS:
   1201       {
   1202         /* database says nothing actually changed, 304 (could
   1203            theoretically happen if another equivalent upload succeeded
   1204            since we last checked!) */
   1205         struct MHD_Response *resp;
   1206         enum MHD_Result ret;
   1207 
   1208         resp = MHD_create_response_from_buffer (0,
   1209                                                 NULL,
   1210                                                 MHD_RESPMEM_PERSISTENT);
   1211         TALER_MHD_add_global_headers (resp,
   1212                                       false);
   1213         GNUNET_break (MHD_YES ==
   1214                       MHD_add_response_header (resp,
   1215                                                "Anastasis-Version",
   1216                                                version_s));
   1217         ret = MHD_queue_response (connection,
   1218                                   MHD_HTTP_NOT_MODIFIED,
   1219                                   resp);
   1220         GNUNET_break (MHD_YES == ret);
   1221         MHD_destroy_response (resp);
   1222         return ret;
   1223       }
   1224     case ANASTASIS_DB_STORE_STATUS_SUCCESS:
   1225       /* generate main (204) standard success reply */
   1226       {
   1227         struct MHD_Response *resp;
   1228         enum MHD_Result ret;
   1229 
   1230         resp = MHD_create_response_from_buffer (0,
   1231                                                 NULL,
   1232                                                 MHD_RESPMEM_PERSISTENT);
   1233         TALER_MHD_add_global_headers (resp,
   1234                                       false);
   1235         GNUNET_break (MHD_YES ==
   1236                       MHD_add_response_header (resp,
   1237                                                ANASTASIS_HTTP_HEADER_POLICY_VERSION,
   1238                                                version_s));
   1239         GNUNET_break (MHD_YES ==
   1240                       MHD_add_response_header (resp,
   1241                                                ANASTASIS_HTTP_HEADER_POLICY_EXPIRATION,
   1242                                                expir_s));
   1243         ret = MHD_queue_response (connection,
   1244                                   MHD_HTTP_NO_CONTENT,
   1245                                   resp);
   1246         GNUNET_break (MHD_YES == ret);
   1247         MHD_destroy_response (resp);
   1248         return ret;
   1249       }
   1250     }
   1251   }
   1252   GNUNET_break (0);
   1253   return MHD_NO;
   1254 }