diff options
| author | Marcello Stanisci <stanisci.m@gmail.com> | 2019-04-08 02:09:23 +0200 | 
|---|---|---|
| committer | Marcello Stanisci <stanisci.m@gmail.com> | 2019-04-08 02:37:46 +0200 | 
| commit | e13a8902f07a7848d09204cd6f1b9736fe3cf885 (patch) | |
| tree | b455d3061e069814b3591497c8d9ecfe2ad446c2 /src/bank-lib/fakebank.c | |
| parent | 9fc380f7c8ebf8b5623718de376c72e6677b93a6 (diff) | |
Put /history[-range] logic in a dedicate file.
Diffstat (limited to 'src/bank-lib/fakebank.c')
| -rw-r--r-- | src/bank-lib/fakebank.c | 954 | 
1 files changed, 17 insertions, 937 deletions
diff --git a/src/bank-lib/fakebank.c b/src/bank-lib/fakebank.c index f3b58fd2..37aae042 100644 --- a/src/bank-lib/fakebank.c +++ b/src/bank-lib/fakebank.c @@ -25,6 +25,7 @@  #include "platform.h"  #include "taler_fakebank_lib.h"  #include "taler_bank_service.h" +#include "fakebank.h"  /**   * Maximum POST request size (for /admin/add/incoming) @@ -33,169 +34,6 @@  /** - * Parse URL arguments of a /history[-range] HTTP request. - * - * @param connection MHD connection object. - * @param ha @a HistoryArgs structure. - */ -#define PARSE_HISTORY_ARGS(connection, ha) \ -  parse_history_args_ (connection, ha, __FUNCTION__) - -/** - * Details about a transcation we (as the simulated bank) received. - */ -struct Transaction -{ -  /** -   * We store transactions in a DLL. -   */ -  struct Transaction *next; - -  /** -   * We store transactions in a DLL. -   */ -  struct Transaction *prev; - -  /** -   * Amount to be transferred. -   */ -  struct TALER_Amount amount; - -  /** -   * Account to debit. -   */ -  uint64_t debit_account; - -  /** -   * Account to credit. -   */ -  uint64_t credit_account; - -  /** -   * Subject of the transfer. -   */ -  char *subject; - -  /** -   * Base URL of the exchange. -   */ -  char *exchange_base_url; - -  /** -   * When did the transaction happen? -   */ -  struct GNUNET_TIME_Absolute date; - -  /** -   * Number of this transaction. -   */ -  uint64_t row_id; - -  /** -   * Flag set if the transfer was rejected. -   */ -  int rejected; - -  /** -   * Has this transaction been subjected to #TALER_FAKEBANK_check() -   * and should thus no longer be counted in -   * #TALER_FAKEBANK_check_empty()? -   */ -  int checked; -}; - - -/** - * Needed to implement ascending/descending ordering - * of /history results. - */ -struct HistoryElement -{ - -  /** -   * History JSON element. -   */ -  json_t *element; - -  /** -   * Previous element. -   */ -  struct HistoryElement *prev; - -  /** -   * Next element. -   */ -  struct HistoryElement *next; -}; - - -/** - * Values to implement the "/history-range" range. - */ -struct HistoryRangeDates -{ -  /** -   * Oldest row in the results. -   */ -  struct GNUNET_TIME_Absolute start; - -  /** -   * Youngest row in the results. -   */ -  struct GNUNET_TIME_Absolute end; -}; - -/** - * Values to implement the "/history" range. - */ -struct HistoryRangeIds -{ - -  /** -   * (Exclusive) row ID for the result set. -   */ -  unsigned long long start; - -  /** -   * How many transactions we want in the result set.  If -   * negative/positive, @a start will be strictly younger/older -   * of any element in the result set. -   */ -  long long count; -}; - - -/** - * This is the "base" structure for both the /history and the - * /history-range API calls. - */ -struct HistoryArgs -{ - -  /** -   * Direction asked by the client: CREDIT / DEBIT / BOTH / CANCEL. -   */ -  enum TALER_BANK_Direction direction; - -  /** -   * Bank account number of the requesting client. -   */ -  unsigned long long account_number; - -  /** -   * Ordering of the results. -   */ -  unsigned int ascending; - -  /** -   * Overloaded type that indicates the "range" to be returned -   * in the results; this can be either a date range, or a -   * starting row id + the count. -   */ -  void *range; -}; - -/**   * Handle for the fake bank.   */  struct TALER_FAKEBANK_Handle @@ -746,442 +584,6 @@ handle_reject (struct TALER_FAKEBANK_Handle *h,    return ret;  } -/*********************************** - * Serving "/history" starts here. * - ***********************************/ - -/** - * Type for a function that decides whether or not - * the history-building loop should iterate once again. - * Typically called from inside the 'while' condition. - * - * @param ha history argument. - * @param pos current position. - * @return GNUNET_YES if the iteration shuold go on. - */ -typedef int (*CheckAdvance) -  (const struct HistoryArgs *ha, -   const struct Transaction *pos); - -/** - * Type for a function that steps over the next element - * in the list of all transactions, after the current @a pos - * _got_ included in the result. - */ -typedef struct Transaction * (*Step) -  (const struct HistoryArgs *ha, -   const struct Transaction *pos); - -/* - * Type for a function that steps over the next element - * in the list of all transactions, after the current @a pos - * did _not_ get included in the result. - */ -typedef struct Transaction * (*Skip) -  (const struct HistoryArgs *ha, -   const struct Transaction *pos); - - - - -/** - * Decides whether the history builder will advance or not - * to the next element. - * - * @param ha history args - * @return GNUNET_YES/NO to advance/not-advance. - */ -static int -handle_history_advance (const struct HistoryArgs *ha, -                        const struct Transaction *pos) -{ -  const struct HistoryRangeIds *hri = ha->range; - -  return (NULL != pos) && (0 != hri->count); -} - - -/** - * Iterates on the "next" element to be processed.  To - * be used when the current element does not get inserted in - * the result. - * - * @param ha history arguments. - * @param pos current element being processed. - * @return the next element to be processed. - */ -static struct Transaction * -handle_history_skip (const struct HistoryArgs *ha, -                     const struct Transaction *pos) -{ -  const struct HistoryRangeIds *hri = ha->range; - -  if (hri->count > 0) -    return pos->next; -  if (hri->count < 0) -    return pos->prev; -  return NULL; -} - - -/** - * Iterates on the "next" element to be processed.  To - * be used when the current element _gets_ inserted in the result. - * - * @param ha history arguments. - * @param pos current element being processed. - * @return the next element to be processed. - */ -static struct Transaction * -handle_history_step (const struct HistoryArgs *ha, -                     const struct Transaction *pos) -{ -  struct HistoryRangeIds *hri = ha->range; - -  if (hri->count > 0) -  { -    hri->count--; -    return pos->next; -  } -  if (hri->count < 0) -  { -    hri->count++; -    return pos->prev; -  } -  return NULL; -} - - -/** - * Decides whether the history builder will advance or not - * to the next element. - * - * @param ha history args - * @return GNUNET_YES/NO to advance/not-advance. - */ -static int -handle_history_range_advance (const struct HistoryArgs *ha, -                              const struct Transaction *pos) -{ -  const struct HistoryRangeDates *hrd = ha->range; - -  if ( (NULL != pos) && -      (pos->date.abs_value_us <= hrd->end.abs_value_us) ) -    return GNUNET_YES; - -  return GNUNET_NO; -} - - -/** - * Iterates towards the "next" element to be processed.  To - * be used when the current element does not get inserted in - * the result. - * - * @param ha history arguments. - * @param pos current element being processed. - * @return the next element to be processed. - */ -static struct Transaction * -handle_history_range_skip (const struct HistoryArgs *ha, -                           const struct Transaction *pos) -{ -  /* Transactions -   * are stored from "head"/older to "tail"/younger.  */ -  return pos->next; -} - -/** - * Iterates on the "next" element to be processed.  To - * be used when the current element _gets_ inserted in the result. - * Same implementation of the "skip" counterpart, as /history-range - * does not have the notion of count/delta. - */ -Step handle_history_range_step = handle_history_range_skip; - -/** - * Actual history response builder. - * - * @param pos first (included) element in the result set. - * @param ha history arguments. - * @param caller_name which function is building the history. - * @return MHD_YES / MHD_NO, after having enqueued the response - *         object into MHD. - */ -static int -build_history_response (struct MHD_Connection *connection, -                        struct Transaction *pos, -                        struct HistoryArgs *ha, -                        Skip skip, -                        Step step, -                        CheckAdvance advance) -{ - -  struct HistoryElement *history_results_head = NULL; -  struct HistoryElement *history_results_tail = NULL; -  struct HistoryElement *history_element = NULL; -  json_t *history; -  json_t *jresponse; -  int ret; - -  while (advance (ha, -                  pos)) -  { -    json_t *trans; -    char *subject; -    const char *sign; - -    GNUNET_log (GNUNET_ERROR_TYPE_INFO, -                "Found transaction over %s from %llu to %llu\n", -                TALER_amount2s (&pos->amount), -                (unsigned long long) pos->debit_account, -                (unsigned long long) pos->credit_account); - -    if ( (! ( ( (ha->account_number == pos->debit_account) && -                (0 != (ha->direction & TALER_BANK_DIRECTION_DEBIT)) ) || -              ( (ha->account_number == pos->credit_account) && -                (0 != (ha->direction & TALER_BANK_DIRECTION_CREDIT) ) ) ) ) || -         ( (0 == (ha->direction & TALER_BANK_DIRECTION_CANCEL)) && -           (GNUNET_YES == pos->rejected) ) ) -    { -      pos = skip (ha, -                  pos); -      continue; -    } - -    GNUNET_asprintf (&subject, -                     "%s %s", -                     pos->subject, -                     pos->exchange_base_url); -    sign = -      (ha->account_number == pos->debit_account) -      ? (pos->rejected ? "cancel-" : "-") -      : (pos->rejected ? "cancel+" : "+"); -    trans = json_pack -      ("{s:I, s:o, s:o, s:s, s:I, s:s}", -       "row_id", (json_int_t) pos->row_id, -       "date", GNUNET_JSON_from_time_abs (pos->date), -       "amount", TALER_JSON_from_amount (&pos->amount), -       "sign", sign, -       "counterpart", (json_int_t) -         ( (ha->account_number == pos->debit_account) -            ? pos->credit_account -            : pos->debit_account), -       "wt_subject", subject); -    GNUNET_assert (NULL != trans); -    GNUNET_free (subject); - -    history_element = GNUNET_new (struct HistoryElement); -    history_element->element = trans; - - -    /* XXX: the ordering feature is missing.  */ - -    GNUNET_CONTAINER_DLL_insert_tail (history_results_head, -                                      history_results_tail, -                                      history_element); -    pos = step (ha, pos); -  } - -  history = json_array (); -  if (NULL != history_results_head) -    history_element = history_results_head; - -  while (NULL != history_element) -  { -    json_array_append_new (history, -                           history_element->element); -    history_element = history_element->next; -    if (NULL != history_element) -      GNUNET_free_non_null (history_element->prev); -  } -  GNUNET_free_non_null (history_results_tail); - -  if (0 == json_array_size (history)) -  { -    struct MHD_Response *resp; - -    json_decref (history); -    GNUNET_log (GNUNET_ERROR_TYPE_INFO, -                "Returning empty transaction history\n"); -    resp = MHD_create_response_from_buffer -      (0, -       "", -       MHD_RESPMEM_PERSISTENT); -    ret = MHD_queue_response (connection, -                              MHD_HTTP_NO_CONTENT, -                              resp); -    MHD_destroy_response (resp); -    return ret; -  } - -  jresponse = json_pack ("{s:o}", -                         "data", -                         history); -  if (NULL == jresponse) -  { -    GNUNET_break (0); -    return MHD_NO; -  } - -  /* Finally build response object */ -  { -    struct MHD_Response *resp; -    void *json_str; -    size_t json_len; - -    json_str = json_dumps (jresponse, -                           JSON_INDENT(2)); -    json_decref (jresponse); -    if (NULL == json_str) -    { -      GNUNET_break (0); -      return MHD_NO; -    } -    json_len = strlen (json_str); -    resp = MHD_create_response_from_buffer (json_len, -                                            json_str, -                                            MHD_RESPMEM_MUST_FREE); -    if (NULL == resp) -    { -      GNUNET_break (0); -      free (json_str); -      return MHD_NO; -    } -    (void) MHD_add_response_header (resp, -                                    MHD_HTTP_HEADER_CONTENT_TYPE, -                                    "application/json"); -    ret = MHD_queue_response (connection, -                              MHD_HTTP_OK, -                              resp); -    MHD_destroy_response (resp); -  } -  return ret; -} - - - -/** - * Parse URL history arguments, of _both_ APIs: - * /history and /history-range. - * - * @param connection MHD connection. - * @param function_name name of the caller. - * @param ha[out] will contain the parsed values. - * @return GNUNET_OK only if the parsing succeedes. - */ -static int -parse_history_common_args (struct MHD_Connection *connection, -                           struct HistoryArgs *ha) -{ -  /** -   * @variable -   * Just check if given and == "basic", no need to keep around. -   */ -  const char *auth; - -  /** -   * All those will go into the structure, after parsing. -   */ -  const char *direction; -  const char *cancelled; -  const char *ordering; -  const char *account_number; - - -  auth = MHD_lookup_connection_value (connection, -                                      MHD_GET_ARGUMENT_KIND, -                                      "auth"); -  direction = MHD_lookup_connection_value (connection, -                                           MHD_GET_ARGUMENT_KIND, -                                           "direction"); -  cancelled = MHD_lookup_connection_value (connection, -                                           MHD_GET_ARGUMENT_KIND, -                                           "cancelled"); -  ordering = MHD_lookup_connection_value (connection, -                                          MHD_GET_ARGUMENT_KIND, -                                          "ordering"); -  account_number = MHD_lookup_connection_value -    (connection, -     MHD_GET_ARGUMENT_KIND, -     "account_number"); - -  /* Fail if one of the above failed.  */ -  if ( (NULL == direction) || -       (NULL == cancelled) || -       ( (0 != strcasecmp (cancelled, -                           "OMIT")) && -         (0 != strcasecmp (cancelled, -                           "SHOW")) ) || -       ( (0 != strcasecmp (direction, -                           "BOTH")) && -         (0 != strcasecmp (direction, -                           "CREDIT")) && -         (0 != strcasecmp (direction, -                           "DEBIT")) ) || -         (1 != sscanf (account_number, -                       "%llu", -                       &ha->account_number)) || -         ( (NULL == auth) || (0 != strcasecmp (auth, -                                               "basic")) ) ) -  { -    /* Invalid request, given that this is fakebank we impolitely -     * just kill the connection instead of returning a nice error. -     */ -    GNUNET_break (0); -    return GNUNET_NO; -  } - -  if (0 == strcasecmp (direction, -                       "CREDIT")) -  { -    ha->direction = TALER_BANK_DIRECTION_CREDIT; -  } -  else if (0 == strcasecmp (direction, -                            "DEBIT")) -  { -    ha->direction = TALER_BANK_DIRECTION_DEBIT; -  } -  else if (0 == strcasecmp (direction, -                            "BOTH")) -  { -    ha->direction = TALER_BANK_DIRECTION_BOTH; -  } - -  /* Direction is invalid.  */ -  else -  { -    GNUNET_break (0); -    return GNUNET_NO; -  } - -  if (0 == strcasecmp (cancelled, -                       "OMIT")) -  { -    /* nothing */ -  } else if (0 == strcasecmp (cancelled, -                              "SHOW")) -  { -    ha->direction |= TALER_BANK_DIRECTION_CANCEL; -  } - -  /* Cancel-showing policy is invalid.  */ -  else -  { -    GNUNET_break (0); -    return GNUNET_NO; -  } - -  if ((NULL != ordering) -      && 0 == strcmp ("ascending", -                      ordering)) -    ha->ascending = GNUNET_YES; -  else -    ha->ascending = GNUNET_NO; - -  return GNUNET_OK; -} -  /**   * Handle incoming HTTP request for /history   * @@ -1201,8 +603,8 @@ handle_history_new (struct TALER_FAKEBANK_Handle *h,    const char *delta;    struct Transaction *pos; -  if (GNUNET_OK != parse_history_common_args (connection, -                                              &ha)) +  if (GNUNET_OK != TFH_parse_history_common_args (connection, +                                                  &ha))    {      GNUNET_break (0);      return MHD_NO; @@ -1259,12 +661,12 @@ handle_history_new (struct TALER_FAKEBANK_Handle *h,    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,                "/history, start row (0 == no transactions exist): %llu\n",                NULL != pos ? pos->row_id : 0); -  return build_history_response (connection, -                                 pos, -                                 &ha, -                                 &handle_history_skip, -                                 &handle_history_step, -                                 &handle_history_advance); +  return TFH_build_history_response (connection, +                                     pos, +                                     &ha, +                                     &TFH_handle_history_skip, +                                     &TFH_handle_history_step, +                                     &TFH_handle_history_advance);  }  /** @@ -1288,7 +690,7 @@ handle_history_range (struct TALER_FAKEBANK_Handle *h,    long long unsigned int end_stamp;     struct Transaction *pos; -  if (GNUNET_OK != parse_history_common_args (connection, +  if (GNUNET_OK != TFH_parse_history_common_args (connection,                                                &ha))    {      GNUNET_break (0); @@ -1309,7 +711,7 @@ handle_history_range (struct TALER_FAKEBANK_Handle *h,                                     &end_stamp)) )    {      GNUNET_break (0); -    return GNUNET_NO; +    return MHD_NO;    }    hrd.start.abs_value_us = start_stamp * 1000LL * 1000LL; @@ -1325,336 +727,14 @@ handle_history_range (struct TALER_FAKEBANK_Handle *h,      if (hrd.start.abs_value_us <= pos->date.abs_value_us)        break;     } -  return build_history_response (connection, -                                 pos, -                                 &ha, -                                 &handle_history_range_skip, -                                 handle_history_range_step, -                                 &handle_history_range_advance); -} - -/** - * Handle incoming HTTP request for /history - * - * @param h the fakebank handle - * @param connection the connection - * @param con_cls place to store state, not used - * @return MHD result code - */ -static int -handle_history (struct TALER_FAKEBANK_Handle *h, -                struct MHD_Connection *connection, -                void **con_cls) -{ -  const char *auth; -  const char *delta; -  const char *start; -  const char *dir; -  const char *acc; -  const char *cancelled; -  const char *ordering; -  unsigned long long account_number; -  unsigned long long start_number; -  long long count; -  enum TALER_BANK_Direction direction; -  struct Transaction *pos; -  json_t *history; -  json_t *jresponse; -  int ret; -  int ascending; -  struct HistoryElement *history_results_head = NULL; -  struct HistoryElement *history_results_tail = NULL; -  struct HistoryElement *history_element = NULL; - -  auth = MHD_lookup_connection_value (connection, -                                      MHD_GET_ARGUMENT_KIND, -                                      "auth"); -  delta = MHD_lookup_connection_value (connection, -                                       MHD_GET_ARGUMENT_KIND, -                                       "delta"); -  dir = MHD_lookup_connection_value (connection, -                                     MHD_GET_ARGUMENT_KIND, -                                     "direction"); -  cancelled = MHD_lookup_connection_value (connection, -                                           MHD_GET_ARGUMENT_KIND, -                                           "cancelled"); -  start = MHD_lookup_connection_value (connection, -                                       MHD_GET_ARGUMENT_KIND, -                                       "start"); -  ordering = MHD_lookup_connection_value (connection, -                                          MHD_GET_ARGUMENT_KIND, -                                          "ordering"); -  acc = MHD_lookup_connection_value (connection, -                                     MHD_GET_ARGUMENT_KIND, -                                     "account_number"); -  if ( (NULL == auth) || -       (0 != strcasecmp (auth, -                         "basic")) || -       (NULL == acc) || -       (NULL == delta) ) -  { -    /* Invalid request, -       given that this is fakebank we impolitely just -       kill the connection instead of returning a nice error. */ -    GNUNET_break (0); -    return MHD_NO; -  } -  start_number = 0; -  if ( (1 != sscanf (delta, -                     "%lld", -                     &count)) || -       (1 != sscanf (acc, -                     "%llu", -                     &account_number)) || -       ( (NULL != start) && -         (1 != sscanf (start, -                       "%llu", -                       &start_number)) ) || -       (NULL == dir) || -       (NULL == cancelled) || -       ( (0 != strcasecmp (cancelled, -                           "OMIT")) && -         (0 != strcasecmp (cancelled, -                           "SHOW")) ) || -       ( (0 != strcasecmp (dir, -                           "BOTH")) && -         (0 != strcasecmp (dir, -                           "CREDIT")) && -         (0 != strcasecmp (dir, -                           "DEBIT")) ) ) -  { -    /* Invalid request, given that this is fakebank we impolitely -     * just kill the connection instead of returning a nice error. -     */ -    GNUNET_break (0); -    return MHD_NO; -  } -  GNUNET_log (GNUNET_ERROR_TYPE_INFO, -              "Client asked for up to %lld results of type %s for account %llu starting at %llu\n", -              count, -              dir, -              (unsigned long long) account_number, -              start_number); -  if (0 == strcasecmp (dir, -                       "CREDIT")) -  { -    direction = TALER_BANK_DIRECTION_CREDIT; -  } -  else if (0 == strcasecmp (dir, -                            "DEBIT")) -  { -    direction = TALER_BANK_DIRECTION_DEBIT; -  } -  else if (0 == strcasecmp (dir, -                            "BOTH")) -  { -    direction = TALER_BANK_DIRECTION_BOTH; -  } -  else -  { -    GNUNET_assert (0); -    return MHD_NO; -  } -  if (0 == strcasecmp (cancelled, -                       "OMIT")) -  { -    /* nothing */ -  } else if (0 == strcasecmp (cancelled, -                              "SHOW")) -  { -    direction |= TALER_BANK_DIRECTION_CANCEL; -  } -  else -  { -    GNUNET_assert (0); -    return MHD_NO; -  } - -  if (NULL == start) -    pos = 0 > count ? h->transactions_tail : h->transactions_head; - -  else if (NULL != h->transactions_head) -  { -    for (pos = h->transactions_head; -         NULL != pos; -         pos = pos->next) -      if (pos->row_id  == start_number) -        break; -    if (NULL == pos) -    { -      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -                  "Invalid range specified, transaction %llu not known!\n", -                  (unsigned long long) start_number); -      return MHD_NO; -    } -    /* range is exclusive, skip the matching entry */ -    if (count > 0) -      pos = pos->next; -    if (count < 0) -      pos = pos->prev; -  } -  else -  { -    /* list is empty */ -    pos = NULL; -  } - -  history = json_array (); -  if ((NULL != ordering) -      && 0 == strcmp ("ascending", -                      ordering)) -    ascending = GNUNET_YES; -  else -    ascending = GNUNET_NO; - -  while ( (NULL != pos) && -          (0 != count) ) -  { -    json_t *trans; -    char *subject; -    const char *sign; - -    GNUNET_log (GNUNET_ERROR_TYPE_INFO, -                "Found transaction over %s from %llu to %llu\n", -                TALER_amount2s (&pos->amount), -                (unsigned long long) pos->debit_account, -                (unsigned long long) pos->credit_account); - -    if ( (! ( ( (account_number == pos->debit_account) && -                (0 != (direction & TALER_BANK_DIRECTION_DEBIT)) ) || -              ( (account_number == pos->credit_account) && -                (0 != (direction & TALER_BANK_DIRECTION_CREDIT) ) ) ) ) || -         ( (0 == (direction & TALER_BANK_DIRECTION_CANCEL)) && -           (GNUNET_YES == pos->rejected) ) ) -    { -      if (count > 0) -        pos = pos->next; -      if (count < 0) -        pos = pos->prev; -      continue; -    } - -    GNUNET_asprintf (&subject, -                     "%s %s", -                     pos->subject, -                     pos->exchange_base_url); -    sign = -      (account_number == pos->debit_account) -      ? (pos->rejected ? "cancel-" : "-") -      : (pos->rejected ? "cancel+" : "+"); -    trans = json_pack ("{s:I, s:o, s:o, s:s, s:I, s:s}", -                       "row_id", (json_int_t) pos->row_id, -                       "date", GNUNET_JSON_from_time_abs (pos->date), -                       "amount", TALER_JSON_from_amount (&pos->amount), -                       "sign", sign, -                       "counterpart", (json_int_t) ( (account_number == pos->debit_account) -                                                     ? pos->credit_account -                                                     : pos->debit_account), -                       "wt_subject", subject); -    GNUNET_assert (NULL != trans); -    GNUNET_free (subject); - -    history_element = GNUNET_new (struct HistoryElement); -    history_element->element = trans; - -    if (((0 < count) && (GNUNET_YES == ascending)) -      || ((0 > count) && (GNUNET_NO == ascending))) -    GNUNET_CONTAINER_DLL_insert_tail (history_results_head, -                                      history_results_tail, -                                      history_element); -    else -      GNUNET_CONTAINER_DLL_insert (history_results_head, -                                   history_results_tail, -                                   history_element); -    if (count > 0) -    { -      pos = pos->next; -      count--; -    } -    if (count < 0) -    { -      pos = pos->prev; -      count++; -    } -  } - -  if (NULL != history_results_head) -    history_element = history_results_head; -  while (NULL != history_element) -  { -    json_array_append_new (history, -                           history_element->element); -    history_element = history_element->next; -    if (NULL != history_element) -      GNUNET_free_non_null (history_element->prev); -  } -  GNUNET_free_non_null (history_results_tail); - -  if (0 == json_array_size (history)) -  { -    struct MHD_Response *resp; - -    json_decref (history); -    GNUNET_log (GNUNET_ERROR_TYPE_INFO, -                "Returning empty transaction history\n"); -    resp = MHD_create_response_from_buffer (0, -                                            "", -                                            MHD_RESPMEM_PERSISTENT); -    ret = MHD_queue_response (connection, -                              MHD_HTTP_NO_CONTENT, -                              resp); -    MHD_destroy_response (resp); -    return ret; -  } - -  jresponse = json_pack ("{s:o}", -                         "data", -                         history); -  if (NULL == jresponse) -  { -    GNUNET_break (0); -    return MHD_NO; -  } - -  /* Finally build response object */ -  { -    struct MHD_Response *resp; -    void *json_str; -    size_t json_len; - -    json_str = json_dumps (jresponse, -                           JSON_INDENT(2)); -    json_decref (jresponse); -    if (NULL == json_str) -    { -      GNUNET_break (0); -      return MHD_NO; -    } -    json_len = strlen (json_str); -    resp = MHD_create_response_from_buffer (json_len, -                                            json_str, -                                            MHD_RESPMEM_MUST_FREE); -    if (NULL == resp) -    { -      GNUNET_break (0); -      free (json_str); -      return MHD_NO; -    } -    (void) MHD_add_response_header (resp, -                                    MHD_HTTP_HEADER_CONTENT_TYPE, -                                    "application/json"); -    ret = MHD_queue_response (connection, -                              MHD_HTTP_OK, -                              resp); -    MHD_destroy_response (resp); -  } -  return ret; +  return TFH_build_history_response (connection, +                                     pos, +                                     &ha, +                                     &TFH_handle_history_range_skip, +                                     TFH_handle_history_range_step, +                                     &TFH_handle_history_range_advance);  } -/*********************************** - * End of /history implementation. * - ***********************************/ -  /**   * Handle incoming HTTP request.   *  | 
