add /history support to fakebank

This commit is contained in:
Christian Grothoff 2017-05-04 23:29:08 +02:00
parent 57964b6ae9
commit 1ea22a37c6
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
3 changed files with 274 additions and 27 deletions

View File

@ -1,6 +1,6 @@
/* /*
This file is part of TALER This file is part of TALER
Copyright (C) 2015, 2016 GNUnet e.V. Copyright (C) 2015, 2016, 2017 GNUnet e.V.
TALER is free software; you can redistribute it and/or modify it under the TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software terms of the GNU General Public License as published by the Free Software

View File

@ -22,6 +22,7 @@
#include "platform.h" #include "platform.h"
#include "taler_fakebank_lib.h" #include "taler_fakebank_lib.h"
#include "taler_bank_service.h"
/** /**
* Maximum POST request size (for /admin/add/incoming) * Maximum POST request size (for /admin/add/incoming)
@ -70,6 +71,16 @@ struct Transaction
* Base URL of the exchange. * Base URL of the exchange.
*/ */
char *exchange_base_url; char *exchange_base_url;
/**
* When did the transaction happen?
*/
struct GNUNET_TIME_Absolute date;
/**
* Number of this transaction.
*/
unsigned long long serial_id;
}; };
@ -97,6 +108,11 @@ struct TALER_FAKEBANK_Handle
* Task running HTTP server for the "test" bank. * Task running HTTP server for the "test" bank.
*/ */
struct GNUNET_SCHEDULER_Task *mhd_task; struct GNUNET_SCHEDULER_Task *mhd_task;
/**
* Number of transactions.
*/
unsigned long long serial_counter;
}; };
@ -257,43 +273,28 @@ handle_mhd_completion_callback (void *cls,
/** /**
* Handle incoming HTTP request. * Handle incoming HTTP request for /admin/add/incoming.
* *
* @param cls closure for MHD daemon (unused) * @param h the fakebank handle
* @param connection the connection * @param connection the connection
* @param url the requested url
* @param method the method (POST, GET, ...)
* @param version HTTP version (ignored)
* @param upload_data request data * @param upload_data request data
* @param upload_data_size size of @a upload_data in bytes * @param upload_data_size size of @a upload_data in bytes
* @param con_cls closure for request (a `struct Buffer *`) * @param con_cls closure for request (a `struct Buffer *`)
* @return MHD result code * @return MHD result code
*/ */
static int static int
handle_mhd_request (void *cls, handle_admin_add_incoming (struct TALER_FAKEBANK_Handle *h,
struct MHD_Connection *connection, struct MHD_Connection *connection,
const char *url,
const char *method,
const char *version,
const char *upload_data, const char *upload_data,
size_t *upload_data_size, size_t *upload_data_size,
void **con_cls) void **con_cls)
{ {
struct TALER_FAKEBANK_Handle *h = cls;
enum GNUNET_JSON_PostResult pr; enum GNUNET_JSON_PostResult pr;
json_t *json; json_t *json;
struct Transaction *t; struct Transaction *t;
struct MHD_Response *resp; struct MHD_Response *resp;
int ret; int ret;
if (0 != strcasecmp (url,
"/admin/add/incoming"))
{
/* Unexpected URI path, just close the connection. */
/* we're rather impolite here, but it's a testcase. */
GNUNET_break_op (0);
return MHD_NO;
}
pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX, pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX,
con_cls, con_cls,
upload_data, upload_data,
@ -336,6 +337,9 @@ handle_mhd_request (void *cls,
return MHD_NO; return MHD_NO;
} }
t->exchange_base_url = GNUNET_strdup (base_url); t->exchange_base_url = GNUNET_strdup (base_url);
t->serial_id = h->serial_counter++;
t->date = GNUNET_TIME_absolute_get ();
GNUNET_TIME_round_abs (&t->date);
GNUNET_CONTAINER_DLL_insert (h->transactions_head, GNUNET_CONTAINER_DLL_insert (h->transactions_head,
h->transactions_tail, h->transactions_tail,
t); t);
@ -355,6 +359,246 @@ handle_mhd_request (void *cls,
} }
/**
* Handle incoming HTTP request for /history
*
* @param h the fakebank handle
* @param connection the connection
* @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;
unsigned long long account_number;
unsigned long long start_number;
long long count;
enum TALER_BANK_Direction direction;
struct Transaction *pos;
json_t *history;
int ret;
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");
start = MHD_lookup_connection_value (connection,
MHD_GET_ARGUMENT_KIND,
"start");
acc = MHD_lookup_connection_value (connection,
MHD_GET_ARGUMENT_KIND,
"account_number");
if ( (NULL == auth) ||
(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;
}
if ( (1 != sscanf (delta,
"%lld",
&count)) ||
(1 != sscanf (acc,
"%llu",
&account_number)) ||
( (NULL != start) &&
(1 != sscanf (start,
"%llu",
&start_number)) ) ||
( (NULL != dir) &&
(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;
}
if (NULL == dir)
direction = TALER_BANK_DIRECTION_BOTH;
else if (0 == strcasecmp (dir, "CREDIT"))
direction = TALER_BANK_DIRECTION_CREDIT;
else
direction = TALER_BANK_DIRECTION_DEBIT;
if (NULL == start)
start_number = (count > 0) ? 0 : UINT64_MAX;
if (UINT64_MAX == start_number)
{
pos = h->transactions_tail;
}
else
{
unsigned long long off = 0;
for (pos = h->transactions_head;
off < start_number;
off++)
{
if (NULL == pos)
{
GNUNET_break (0);
return MHD_NO;
}
pos = pos->next;
}
GNUNET_assert (pos->serial_id == start_number);
}
history = json_array ();
while ( (NULL != pos) &&
(0 != count) )
{
json_t *trans;
char *subject;
if (! ( ( (account_number == pos->debit_account) &&
(0 != (direction & TALER_BANK_DIRECTION_DEBIT)) ) ||
( (account_number == pos->credit_account) &&
(0 != (direction & TALER_BANK_DIRECTION_CREDIT) ) ) ) )
{
if (count > 0)
pos = pos->next;
if (count < 0)
pos = pos->prev;
continue;
}
subject = GNUNET_STRINGS_data_to_string_alloc (&pos->wtid,
sizeof (pos->wtid));
trans = json_pack ("{s:I, s:o, s:o, s:s, s:I, s:s}",
"row_id", (json_int_t) pos->serial_id,
"date", GNUNET_JSON_from_time_abs (pos->date),
"amount", TALER_JSON_from_amount (&pos->amount),
"sign", (account_number == pos->debit_account) ? "-" : "+",
"counterpart", (json_int_t) ( (account_number == pos->debit_account)
? pos->credit_account
: pos->debit_account),
"wt_subject", subject);
GNUNET_free (subject);
json_array_append (history,
trans);
if (count > 0)
{
pos = pos->next;
count--;
}
if (count < 0)
{
pos = pos->prev;
count++;
}
}
if (0 == json_array_size (history))
{
struct MHD_Response *resp;
json_decref (history);
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;
}
/* Finally build response object */
{
struct MHD_Response *resp;
void *json_str;
size_t json_len;
json_str = json_dumps (history,
JSON_INDENT(2));
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;
}
ret = MHD_queue_response (connection,
MHD_HTTP_OK,
resp);
MHD_destroy_response (resp);
}
return ret;
}
/**
* Handle incoming HTTP request.
*
* @param cls a `struct TALER_FAKEBANK_Handle`
* @param connection the connection
* @param url the requested url
* @param method the method (POST, GET, ...)
* @param version HTTP version (ignored)
* @param upload_data request data
* @param upload_data_size size of @a upload_data in bytes
* @param con_cls closure for request (a `struct Buffer *`)
* @return MHD result code
*/
static int
handle_mhd_request (void *cls,
struct MHD_Connection *connection,
const char *url,
const char *method,
const char *version,
const char *upload_data,
size_t *upload_data_size,
void **con_cls)
{
struct TALER_FAKEBANK_Handle *h = cls;
if ( (0 == strcasecmp (url,
"/admin/add/incoming")) &&
(0 == strcasecmp (method,
MHD_HTTP_METHOD_POST)) )
return handle_admin_add_incoming (h,
connection,
upload_data,
upload_data_size,
con_cls);
if ( (0 == strcasecmp (url,
"/history")) &&
(0 == strcasecmp (method,
MHD_HTTP_METHOD_GET)) )
return handle_history (h,
connection,
con_cls);
/* Unexpected URI path, just close the connection. */
/* we're rather impolite here, but it's a testcase. */
GNUNET_break_op (0);
return MHD_NO;
}
/** /**
* Task run whenever HTTP server operations are pending. * Task run whenever HTTP server operations are pending.
* *
@ -466,3 +710,6 @@ TALER_FAKEBANK_start (uint16_t port)
schedule_httpd (h); schedule_httpd (h);
return h; return h;
} }
/* end of fakebank.c */