twister

HTTP fault injector for testing
Log | Files | Refs | README | LICENSE

twister_api.c (19059B)


      1 /*
      2   This file is part of Taler.
      3   Copyright (C) 2009, 2010, 2011, 2016 GNUnet e.V.
      4   Copyright (C) 2018 Taler Systems SA
      5 
      6   Taler is free software; you can redistribute it and/or modify
      7   it under the terms of the GNU General Public License as
      8   published by the Free Software Foundation; either version 3,
      9   or (at your option) any later version.
     10 
     11   Taler is distributed in the hope that it will be useful, but
     12   WITHOUT ANY WARRANTY; without even the implied warranty of
     13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     14   See the GNU General Public License for more details.
     15 
     16   You should have received a copy of the GNU General Public
     17   License along with Taler; see the file COPYING.  If not,
     18   write to the Free Software Foundation, Inc., 51 Franklin
     19   Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
     20 
     21 /**
     22  * @file twister_api.c
     23  * @brief api to control twister proxy
     24  * @author Christian Grothoff
     25  * @author Marcello Stanisci
     26  */
     27 #include "platform.h"
     28 #include <gnunet/gnunet_util_lib.h>
     29 #include <microhttpd.h>
     30 #include "taler_twister_service.h"
     31 #include "twister.h"
     32 
     33 #define LOG(kind,...) \
     34   GNUNET_log_from (kind, "twister-api",__VA_ARGS__)
     35 
     36 
     37 /**
     38  * Opaque handle for asynchronous operation.
     39  */
     40 struct TALER_TWISTER_Operation
     41 {
     42 
     43   /**
     44    * Pointer to next operation.
     45    */
     46   struct TALER_TWISTER_Operation *next;
     47 
     48   /**
     49    * Pointer to previous operation.
     50    */
     51   struct TALER_TWISTER_Operation *prev;
     52 
     53   /**
     54    * Pointer to main handle (= connection to the twister).
     55    */
     56   struct TALER_TWISTER_Handle *h;
     57 
     58   /**
     59    * Callback for this operation.
     60    */
     61   GNUNET_SCHEDULER_TaskCallback cb;
     62 
     63   /**
     64    * Closure to pass the callback above.
     65    */
     66   void *cb_cls;
     67 };
     68 
     69 
     70 /**
     71  * Handle for talking with the Twister service.
     72  */
     73 struct TALER_TWISTER_Handle
     74 {
     75   /**
     76    * Configuration to use.
     77    */
     78   const struct GNUNET_CONFIGURATION_Handle *cfg;
     79 
     80   /**
     81    * Message queue (if available).
     82    */
     83   struct GNUNET_MQ_Handle *mq;
     84 
     85   /**
     86    * First pending operation.
     87    */
     88   struct TALER_TWISTER_Operation *op_head;
     89 
     90   /**
     91    * Last pending operation.
     92    */
     93   struct TALER_TWISTER_Operation *op_tail;
     94 };
     95 
     96 
     97 /**
     98  * Generic error handler, called with the appropriate
     99  * error code and the same closure specified at the creation of
    100  * the message queue.
    101  * Not every message queue implementation supports an error handler.
    102  *
    103  * @param cls closure with the `struct TALER_TWISTER_Handle *`
    104  * @param error error code
    105  */
    106 static void
    107 mq_error_handler (void *cls,
    108                   enum GNUNET_MQ_Error error)
    109 {
    110   struct TALER_TWISTER_Handle *h = cls;
    111 
    112   GNUNET_MQ_destroy (h->mq);
    113   h->mq = NULL;
    114   /* FIXME: maybe give test case nicer way to shut down... */
    115   GNUNET_assert (0);
    116 }
    117 
    118 
    119 /**
    120  * Type of a function to call when we receive a message
    121  * from the service.
    122  *
    123  * @param cls closure
    124  * @param client_msg message received
    125  */
    126 static void
    127 handle_acknowledgement (void *cls,
    128                         const struct GNUNET_MessageHeader *ack)
    129 {
    130   struct TALER_TWISTER_Handle *h = cls;
    131   struct TALER_TWISTER_Operation *op;
    132 
    133   op = h->op_head;
    134   GNUNET_assert (NULL != op); /* twister very wrong, fail test */
    135   GNUNET_CONTAINER_DLL_remove (h->op_head,
    136                                h->op_tail,
    137                                op);
    138   if (NULL != op->cb)
    139     op->cb (op->cb_cls);
    140   GNUNET_free (op);
    141 }
    142 
    143 
    144 /**
    145  * Connect to the twister service.
    146  *
    147  * @param cfg the configuration to use
    148  * @return handle to use in #TALER_TWISTER_disconnect to disconnect
    149  */
    150 struct TALER_TWISTER_Handle *
    151 TALER_TWISTER_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
    152 {
    153   struct TALER_TWISTER_Handle *h;
    154 
    155   h = GNUNET_new (struct TALER_TWISTER_Handle);
    156   h->cfg = cfg;
    157   {
    158     struct GNUNET_MQ_MessageHandler handlers[] = {
    159       GNUNET_MQ_hd_fixed_size
    160         (acknowledgement,
    161         TWISTER_MESSAGE_TYPE_ACKNOWLEDGEMENT,
    162         struct GNUNET_MessageHeader,
    163         h),
    164       GNUNET_MQ_handler_end ()
    165     };
    166 
    167     LOG (GNUNET_ERROR_TYPE_DEBUG,
    168          "Connecting to twister service.\n");
    169     h->mq = GNUNET_CLIENT_connect (h->cfg,
    170                                    "twister",
    171                                    handlers,
    172                                    &mq_error_handler,
    173                                    h);
    174   }
    175   if (NULL == h->mq)
    176   {
    177     LOG (GNUNET_ERROR_TYPE_ERROR,
    178          "Could not connect to twister service\n");
    179     GNUNET_free (h);
    180     return NULL;
    181   }
    182   return h;
    183 }
    184 
    185 
    186 /**
    187  * Disconnect from twister service.
    188  *
    189  * @param h handle to destroy
    190  */
    191 void
    192 TALER_TWISTER_disconnect (struct TALER_TWISTER_Handle *h)
    193 {
    194   struct TALER_TWISTER_Operation *op;
    195 
    196   while (NULL != (op = h->op_head))
    197   {
    198     GNUNET_CONTAINER_DLL_remove (h->op_head,
    199                                  h->op_tail,
    200                                  op);
    201     GNUNET_free (op);
    202   }
    203   if (NULL != h->mq)
    204   {
    205     GNUNET_MQ_destroy (h->mq);
    206     h->mq = NULL;
    207   }
    208   GNUNET_free (h);
    209 }
    210 
    211 
    212 /**
    213  * Abort operation.  Twister behavior may then include the
    214  * changes requested by the operation, or not!  Must be called
    215  * before the operation callback was invoked.
    216  *
    217  * @param op operation to cancel,
    218  *        operation's callback will not be called
    219  */
    220 void
    221 TALER_TWISTER_cancel (struct TALER_TWISTER_Operation *op)
    222 {
    223   /* Just don't call the callback anymore */
    224   op->cb = NULL;
    225 }
    226 
    227 
    228 /**
    229  * Randomly truncate the request.
    230  *
    231  * @param h twister instance to control
    232  * @param cb function to call once twister is ready; typically
    233  *        a acknowledge function.
    234  * @param cb_cls closure for @a cb
    235  * @return operation handle (to possibly abort)
    236  */
    237 struct TALER_TWISTER_Operation *
    238 TALER_TWISTER_malform_upload (struct TALER_TWISTER_Handle *h,
    239                               GNUNET_SCHEDULER_TaskCallback cb,
    240                               void *cb_cls)
    241 {
    242   struct TALER_TWISTER_Operation *op;
    243   struct GNUNET_MQ_Envelope *env;
    244   struct TWISTER_Malform *src;
    245 
    246   op = GNUNET_new (struct TALER_TWISTER_Operation);
    247   op->h = h;
    248   op->cb = cb;
    249   op->cb_cls = cb_cls;
    250   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
    251                                     h->op_tail,
    252                                     op);
    253   /* Prepare *env*elope. */
    254   env = GNUNET_MQ_msg
    255           (src, TWISTER_MESSAGE_TYPE_MALFORM_UPLOAD);
    256   /* Send message. */
    257   GNUNET_MQ_send (h->mq, env);
    258   LOG (GNUNET_ERROR_TYPE_DEBUG,
    259        "Batching a (upload) body malformation\n");
    260   return op;
    261 }
    262 
    263 
    264 /**
    265  * Randomly truncate the response.
    266  *
    267  * @param h twister instance to control
    268  * @param cb function to call once twister has processed this
    269  *           request.
    270  * @param cb_cls closure for @a cb
    271  * @return operation handle (to possibly abort)
    272  */
    273 struct TALER_TWISTER_Operation *
    274 TALER_TWISTER_malform (struct TALER_TWISTER_Handle *h,
    275                        GNUNET_SCHEDULER_TaskCallback cb,
    276                        void *cb_cls)
    277 {
    278   struct TALER_TWISTER_Operation *op;
    279   struct GNUNET_MQ_Envelope *env;
    280   struct TWISTER_Malform *src;
    281 
    282   op = GNUNET_new (struct TALER_TWISTER_Operation);
    283   op->h = h;
    284   op->cb = cb;
    285   op->cb_cls = cb_cls;
    286   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
    287                                     h->op_tail,
    288                                     op);
    289   /* Prepare *env*elope. */
    290   env = GNUNET_MQ_msg
    291           (src, TWISTER_MESSAGE_TYPE_MALFORM);
    292   /* Send message. */
    293   GNUNET_MQ_send (h->mq, env);
    294   LOG (GNUNET_ERROR_TYPE_DEBUG,
    295        "Batching a body malformation\n");
    296   return op;
    297 }
    298 
    299 
    300 /**
    301  * Instruct the twister to flip a character into
    302  * the string JSON field that belongs to the object
    303  * being returned to the HTTP client.
    304  *
    305  * @param h twister instance to control
    306  * @param path object-like notation to point the string
    307  *        object where we seek a character to flip.
    308  * @param cb function to call once twister has processed this
    309  *        request
    310  * @param cb_cls closure for @a cb
    311  * @return operation handle (to possibly abort)
    312  */
    313 struct TALER_TWISTER_Operation *
    314 TALER_TWISTER_flip_download (struct TALER_TWISTER_Handle *h,
    315                              const char *path,
    316                              GNUNET_SCHEDULER_TaskCallback cb,
    317                              void *cb_cls)
    318 {
    319   struct TALER_TWISTER_Operation *op;
    320   struct GNUNET_MQ_Envelope *env;
    321   struct TWISTER_FlipPath *src; // FIXME 'src' right name?
    322   uint16_t stralloc;
    323 
    324   stralloc = strlen (path) + 1;
    325   if (stralloc + sizeof (struct TWISTER_FlipPath) > UINT16_MAX)
    326   {
    327     GNUNET_break (0);
    328     return NULL;
    329   }
    330   op = GNUNET_new (struct TALER_TWISTER_Operation);
    331   op->h = h;
    332   op->cb = cb;
    333   op->cb_cls = cb_cls;
    334   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
    335                                     h->op_tail,
    336                                     op);
    337   env = GNUNET_MQ_msg_extra (src,
    338                              stralloc,
    339                              TWISTER_MESSAGE_TYPE_FLIP_PATH_DL);
    340   GNUNET_assert
    341     (stralloc == GNUNET_STRINGS_buffer_fill ((char *) &src[1],
    342                                              stralloc,
    343                                              1,
    344                                              path));
    345   GNUNET_MQ_send (h->mq, env);
    346   return op;
    347 }
    348 
    349 
    350 /**
    351  * Instruct the twister to flip a character into
    352  * the string JSON field that belongs to the object
    353  * being uploaded to the proxied service.
    354  *
    355  * @param h twister instance to control
    356  * @param path object-like notation to point the string
    357  *        object where we seek a character to flip.
    358  * @param cb function to call once twister has batched this
    359  *        request
    360  * @param cb_cls closure for @a cb
    361  * @return operation handle (to possibly abort)
    362  */
    363 struct TALER_TWISTER_Operation *
    364 TALER_TWISTER_flip_upload (struct TALER_TWISTER_Handle *h,
    365                            const char *path,
    366                            GNUNET_SCHEDULER_TaskCallback cb,
    367                            void *cb_cls)
    368 {
    369   struct TALER_TWISTER_Operation *op;
    370   struct GNUNET_MQ_Envelope *env;
    371   struct TWISTER_FlipPath *src; // FIXME 'src' right name?
    372   uint16_t stralloc = strlen (path) + 1;
    373 
    374   if (stralloc + sizeof (struct TWISTER_FlipPath) > UINT16_MAX)
    375   {
    376     GNUNET_break (0);
    377     return NULL;
    378   }
    379   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    380               "Will UL-flip: %s\n",
    381               path);
    382 
    383   op = GNUNET_new (struct TALER_TWISTER_Operation);
    384   op->h = h;
    385   op->cb = cb;
    386   op->cb_cls = cb_cls;
    387   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
    388                                     h->op_tail,
    389                                     op);
    390 
    391   env = GNUNET_MQ_msg_extra (src,
    392                              stralloc,
    393                              TWISTER_MESSAGE_TYPE_FLIP_PATH_UL);
    394   GNUNET_assert
    395     (stralloc == GNUNET_STRINGS_buffer_fill ((char *) &src[1],
    396                                              stralloc,
    397                                              1,
    398                                              path));
    399   GNUNET_MQ_send (h->mq, env);
    400   return op;
    401 }
    402 
    403 
    404 /**
    405  * Delete the object pointed to by @a path.  Note, this
    406  * object belongs to the JSON response object.
    407  *
    408  * @param h twister instance to control
    409  * @param path object-like notation to point the object to be
    410           deleted.  E.g., the path "f1.f2.0" will delete the object
    411           {"f1": {"f2": [{"to be": "deleted"}]}}.
    412  * @param cb function to call once twister is ready
    413  * @param cb_cls closure for @a cb
    414  * @return operation handle (to possibly abort)
    415  */
    416 struct TALER_TWISTER_Operation *
    417 TALER_TWISTER_delete_path (struct TALER_TWISTER_Handle *h,
    418                            const char *path,
    419                            GNUNET_SCHEDULER_TaskCallback cb,
    420                            void *cb_cls)
    421 {
    422   struct TALER_TWISTER_Operation *op;
    423   struct GNUNET_MQ_Envelope *env;
    424   struct TWISTER_DeletePath *src; // FIXME 'src' right name?
    425   uint16_t stralloc;
    426 
    427   stralloc = strlen (path) + 1;
    428   if (stralloc + sizeof (struct TWISTER_DeletePath) > UINT16_MAX)
    429   {
    430     GNUNET_break (0);
    431     return NULL;
    432   }
    433   op = GNUNET_new (struct TALER_TWISTER_Operation);
    434   op->h = h;
    435   op->cb = cb;
    436   op->cb_cls = cb_cls;
    437   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
    438                                     h->op_tail,
    439                                     op);
    440   env = GNUNET_MQ_msg_extra (src,
    441                              stralloc,
    442                              TWISTER_MESSAGE_TYPE_DELETE_PATH);
    443   GNUNET_assert
    444     (stralloc == GNUNET_STRINGS_buffer_fill ((char *) &src[1],
    445                                              stralloc,
    446                                              1,
    447                                              path));
    448   GNUNET_MQ_send (h->mq, env);
    449   return op;
    450 }
    451 
    452 
    453 /**
    454  * Change the response field pointed by @a modify_path with
    455  * @a modify_value.
    456  *
    457  * @param h twister instance to control
    458  * @param path object-like notation path to the object to modify
    459  * @param value value to use for @a modify_path
    460  * @param cb callback to call once twister gets this instruction.
    461  * @param cb_cls closure for @a cb_callback
    462  *
    463  * @return operation handle.
    464  */
    465 struct TALER_TWISTER_Operation *
    466 TALER_TWISTER_modify_path_dl (struct TALER_TWISTER_Handle *h,
    467                               const char *path,
    468                               const char *value,
    469                               GNUNET_SCHEDULER_TaskCallback cb,
    470                               void *cb_cls)
    471 {
    472   struct TALER_TWISTER_Operation *op;
    473   struct GNUNET_MQ_Envelope *env;
    474   struct TWISTER_ModifyPath *src;
    475   uint16_t stralloc;
    476 
    477   stralloc = strlen (path) + strlen (value) + 2;
    478   if (sizeof (*src) + stralloc > UINT16_MAX)
    479   {
    480     GNUNET_break (0);
    481     return NULL;
    482   }
    483   op = GNUNET_new (struct TALER_TWISTER_Operation);
    484   op->h = h;
    485   op->cb = cb;
    486   op->cb_cls = cb_cls;
    487   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
    488                                     h->op_tail,
    489                                     op);
    490   env = GNUNET_MQ_msg_extra (src,
    491                              stralloc,
    492                              TWISTER_MESSAGE_TYPE_MODIFY_PATH_DL);
    493 
    494   GNUNET_assert (stralloc ==
    495                  GNUNET_STRINGS_buffer_fill ((char *) &src[1],
    496                                              stralloc,
    497                                              2,
    498                                              path,
    499                                              value));
    500   GNUNET_MQ_send (h->mq, env);
    501   return op;
    502 }
    503 
    504 
    505 /**
    506  * Change the JSON field pointed by @a path to the new @a value.
    507  * It only applies to upload objects.
    508  *
    509  * @param h twister instance to control
    510  * @param path object-like notation path to the object to modify
    511  * @param value value to use for @a modify_path
    512  * @param cb callback to call once twister gets this instruction.
    513  * @param cb_cls closure for @a cb_callback
    514  *
    515  * @return operation handle.
    516  */
    517 struct TALER_TWISTER_Operation *
    518 TALER_TWISTER_modify_path_ul (struct TALER_TWISTER_Handle *h,
    519                               const char *path,
    520                               const char *value,
    521                               GNUNET_SCHEDULER_TaskCallback cb,
    522                               void *cb_cls)
    523 {
    524   struct TALER_TWISTER_Operation *op;
    525   struct GNUNET_MQ_Envelope *env;
    526   struct TWISTER_ModifyPath *src;
    527   uint16_t stralloc;
    528 
    529   stralloc = strlen (path) + strlen (value) + 2;
    530   if (sizeof (*src) + stralloc > UINT16_MAX)
    531   {
    532     GNUNET_break (0);
    533     return NULL;
    534   }
    535   op = GNUNET_new (struct TALER_TWISTER_Operation);
    536   op->h = h;
    537   op->cb = cb;
    538   op->cb_cls = cb_cls;
    539   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
    540                                     h->op_tail,
    541                                     op);
    542   env = GNUNET_MQ_msg_extra (src,
    543                              stralloc,
    544                              TWISTER_MESSAGE_TYPE_MODIFY_PATH_UL);
    545   GNUNET_assert (stralloc ==
    546                  GNUNET_STRINGS_buffer_fill ((char *) &src[1],
    547                                              stralloc,
    548                                              2,
    549                                              path,
    550                                              value));
    551   GNUNET_MQ_send (h->mq, env);
    552   return op;
    553 }
    554 
    555 
    556 /**
    557  * Change the HTTP response header of @a header to @a value.
    558  *
    559  * @param h twister instance to control
    560  * @param header the HTTP response header to modify
    561  * @param value value to use for @a header
    562  * @param cb callback to call once twister gets this instruction.
    563  * @param cb_cls closure for @a cb_callback
    564  *
    565  * @return operation handle.
    566  */
    567 struct TALER_TWISTER_Operation *
    568 TALER_TWISTER_modify_header_dl (struct TALER_TWISTER_Handle *h,
    569                                 const char *header,
    570                                 const char *value,
    571                                 GNUNET_SCHEDULER_TaskCallback cb,
    572                                 void *cb_cls)
    573 {
    574   struct TALER_TWISTER_Operation *op;
    575   struct GNUNET_MQ_Envelope *env;
    576   struct TWISTER_ModifyPath *src;
    577   uint16_t stralloc;
    578 
    579   if ( (0 == strcasecmp (header,
    580                          MHD_HTTP_HEADER_CONNECTION)) &&
    581        (0 == strcasecmp (value,
    582                          "Keep-Alive")) )
    583   {
    584     GNUNET_break (0);
    585     return NULL;
    586   }
    587   if (0 == strcasecmp (header,
    588                        MHD_HTTP_HEADER_CONTENT_LENGTH))
    589   {
    590     GNUNET_break (0);
    591     return NULL;
    592   }
    593   stralloc = strlen (header) + strlen (value) + 2;
    594   if (sizeof (*src) + stralloc > UINT16_MAX)
    595   {
    596     GNUNET_break (0);
    597     return NULL;
    598   }
    599   op = GNUNET_new (struct TALER_TWISTER_Operation);
    600   op->h = h;
    601   op->cb = cb;
    602   op->cb_cls = cb_cls;
    603   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
    604                                     h->op_tail,
    605                                     op);
    606   env = GNUNET_MQ_msg_extra (src,
    607                              stralloc,
    608                              TWISTER_MESSAGE_TYPE_MODIFY_HEADER_DL);
    609 
    610   GNUNET_assert (stralloc ==
    611                  GNUNET_STRINGS_buffer_fill ((char *) &src[1],
    612                                              stralloc,
    613                                              2,
    614                                              header,
    615                                              value));
    616   GNUNET_MQ_send (h->mq, env);
    617   return op;
    618 }
    619 
    620 
    621 /**
    622  * Change the next response code to @a new_rc.
    623  *
    624  * @param h twister instance to control
    625  * @param new_rc response code to return from the next response
    626  * @param cb function to call once twister is ready
    627  * @param cb_cls closure for @a cb
    628  * @return operation handle (to possibly abort)
    629  */
    630 struct TALER_TWISTER_Operation *
    631 TALER_TWISTER_change_response_code (struct TALER_TWISTER_Handle *h,
    632                                     unsigned int new_rc,
    633                                     GNUNET_SCHEDULER_TaskCallback cb,
    634                                     void *cb_cls)
    635 {
    636   struct TALER_TWISTER_Operation *op;
    637   struct GNUNET_MQ_Envelope *env;
    638   struct TWISTER_SetResponseCode *src;
    639 
    640   op = GNUNET_new (struct TALER_TWISTER_Operation);
    641   op->h = h;
    642   op->cb = cb;
    643   op->cb_cls = cb_cls;
    644   GNUNET_CONTAINER_DLL_insert_tail (h->op_head,
    645                                     h->op_tail,
    646                                     op);
    647   /* Prepare *env*elope. */
    648   env = GNUNET_MQ_msg
    649           (src, TWISTER_MESSAGE_TYPE_SET_RESPONSE_CODE);
    650   /* Put data into the envelope. */
    651   src->response_code = htonl ((uint32_t) new_rc);
    652   /* Send message. */
    653   GNUNET_MQ_send (h->mq, env);
    654   return op;
    655 }
    656 
    657 
    658 /* end of twister_api.c */