commit 7467b99c3c29ab607a5b476a3c93821d8d3a26d4
parent de59cf30a257dd7f7ca68306741eb6dea6046722
Author: Christian Grothoff <christian@grothoff.org>
Date: Wed, 9 Apr 2025 13:18:51 +0200
implement JSON support for kyc-upload (fixes #9715)
Diffstat:
4 files changed, 18 insertions(+), 289 deletions(-)
diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c
@@ -1837,6 +1837,13 @@ handle_mhd_request (void *cls,
.nargs = 1
},
{
+ .url = "kyc-upload",
+ .method = MHD_HTTP_METHOD_POST,
+ .handler.post = &TEH_handler_kyc_upload,
+ .nargs = 1,
+ .nargs_is_upper_bound = true
+ },
+ {
.url = "kyc-webhook",
.method = MHD_HTTP_METHOD_POST,
.handler.post = &TEH_handler_kyc_webhook_post,
@@ -2118,56 +2125,6 @@ handle_mhd_request (void *cls,
return ret;
}
}
- /* FIXME: Why is this handled separately? Fix or justify! */
- if (0 == strncmp (url,
- "/kyc-upload/",
- strlen ("/kyc-upload/")))
- {
- if (0 == strcasecmp (method,
- MHD_HTTP_METHOD_OPTIONS))
- {
- GNUNET_async_scope_restore (&old_scope);
- return TALER_MHD_reply_cors_preflight (connection);
- }
- if (0 != strcasecmp (method,
- MHD_HTTP_METHOD_POST))
- {
- MHD_RESULT ret;
- struct MHD_Response *reply;
-
- reply = TALER_MHD_make_error (TALER_EC_GENERIC_METHOD_INVALID,
- method);
- GNUNET_break (MHD_YES ==
- MHD_add_response_header (reply,
- MHD_HTTP_HEADER_ALLOW,
- MHD_HTTP_METHOD_POST));
- ret = MHD_queue_response (connection,
- MHD_HTTP_METHOD_NOT_ALLOWED,
- reply);
- MHD_destroy_response (reply);
- GNUNET_async_scope_restore (&old_scope);
- return ret;
- }
- {
- MHD_RESULT ret;
-
- ret = TEH_handler_kyc_upload (rc,
- &url[strlen ("/kyc-upload/")],
- upload_data_size,
- upload_data);
- if (GNUNET_OK !=
- TEH_plugin->preflight (TEH_plugin->cls))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Handler %s left open database transaction behind!\n",
- url);
- GNUNET_assert (0);
- }
- GNUNET_async_scope_restore (&old_scope);
- return ret;
- }
- }
-
/* No handler matches, generate not found */
{
diff --git a/src/exchange/taler-exchange-httpd_kyc-upload.c b/src/exchange/taler-exchange-httpd_kyc-upload.c
@@ -22,14 +22,6 @@
#include "taler-exchange-httpd_common_kyc.h"
#include "taler-exchange-httpd_kyc-upload.h"
-/**
- * Size of the MHD post processor upload buffer. Rather large, as we expect
- * large documents. Note that we *additionally* do stream processing, so the
- * actual uploads can be larger and are bounded (globally) by
- * #TALER_MHD_REQUEST_BUFFER_MAX.
- */
-#define UPLOAD_BUFFER_SIZE (1024 * 1024)
-
/**
* Context used for processing the KYC upload req
@@ -74,11 +66,6 @@ struct UploadContext
struct MHD_Response *response;
/**
- * Our post processor.
- */
- struct MHD_PostProcessor *pp;
-
- /**
* Request we are processing.
*/
struct TEH_RequestContext *rc;
@@ -91,37 +78,7 @@ struct UploadContext
/**
* Uploaded data, in JSON.
*/
- json_t *result;
-
- /**
- * Last key in upload.
- */
- char *last_key;
-
- /**
- * Name of the file, possibly NULL.
- */
- char *filename;
-
- /**
- * Content type, possibly NULL.
- */
- char *content_type;
-
- /**
- * Current upload data.
- */
- char *curr_buf;
-
- /**
- * Size of @e curr_buf allocation.
- */
- size_t buf_size;
-
- /**
- * Number of bytes of actual data in @a curr_buf.
- */
- size_t buf_pos;
+ const json_t *result;
};
@@ -153,81 +110,6 @@ TEH_kyc_upload_cleanup ()
/**
- * Check if the upload data is in binary and thus
- * must be base32-encoded.
- *
- * @param uc upload context with data to eval
- */
-static bool
-is_binary (const struct UploadContext *uc)
-{
- if (NULL != memchr (uc->curr_buf,
- '\0',
- uc->buf_pos))
- return true;
- if (NULL != uc->filename)
- return true; /* we always encode all files */
- if (NULL == uc->content_type)
- return false; /* fingers crossed */
- if (0 == strncmp (uc->content_type,
- "text/",
- strlen ("text/")))
- return false; /* good */
- return true;
-}
-
-
-/**
- * Finish processing the data in @a uc under the current
- * key.
- *
- * @param[in,out] uc upload context with key to process
- */
-static void
-finish_key (struct UploadContext *uc)
-{
- json_t *val;
-
- if (NULL == uc->last_key)
- return; /* nothing to do */
- if (is_binary (uc))
- {
- val = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_string ("filename",
- uc->filename)),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_string ("content_type",
- uc->content_type)),
- GNUNET_JSON_pack_data_varsize ("data",
- uc->curr_buf,
- uc->buf_pos)
- );
- }
- else
- {
- val = GNUNET_JSON_PACK (
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_string ("content_type",
- uc->content_type)),
- GNUNET_JSON_pack_string ("text",
- uc->curr_buf));
- }
- GNUNET_assert (0 ==
- json_object_set_new (uc->result,
- uc->last_key,
- val));
- GNUNET_free (uc->last_key);
- GNUNET_free (uc->filename);
- GNUNET_free (uc->content_type);
- memset (uc->curr_buf,
- 0,
- uc->buf_pos);
- uc->buf_pos = 0;
-}
-
-
-/**
* Function called to clean up upload context.
*
* @param[in,out] rc context to clean up
@@ -247,89 +129,11 @@ upload_cleaner (struct TEH_RequestContext *rc)
MHD_destroy_response (uc->response);
uc->response = NULL;
}
- MHD_destroy_post_processor (uc->pp);
- GNUNET_free (uc->filename);
- GNUNET_free (uc->content_type);
- GNUNET_free (uc->last_key);
- GNUNET_free (uc->curr_buf);
- json_decref (uc->result);
GNUNET_free (uc);
}
/**
- * Iterator over key-value pairs where the value may be made available in
- * increments and/or may not be zero-terminated. Used for processing POST
- * data.
- *
- * @param cls user-specified closure
- * @param kind type of the value, always #MHD_POSTDATA_KIND when called from MHD
- * @param key 0-terminated key for the value, NULL if not known. This value
- * is never NULL for url-encoded POST data.
- * @param filename name of the uploaded file, NULL if not known
- * @param content_type mime-type of the data, NULL if not known
- * @param transfer_encoding encoding of the data, NULL if not known
- * @param data pointer to @a size bytes of data at the
- * specified offset
- * @param off offset of data in the overall value
- * @param size number of bytes in @a data available
- * @return #MHD_YES to continue iterating,
- * #MHD_NO to abort the iteration
- */
-static enum MHD_Result
-post_helper (void *cls,
- enum MHD_ValueKind kind,
- const char *key,
- const char *filename,
- const char *content_type,
- const char *transfer_encoding,
- const char *data,
- uint64_t off,
- size_t size)
-{
- struct UploadContext *uc = cls;
-
- if ( (NULL != uc->last_key) &&
- (0 != strcmp (key,
- uc->last_key)) )
- finish_key (uc);
- if (NULL == uc->last_key)
- {
- uc->last_key = GNUNET_strdup (key);
- if (NULL != filename)
- uc->filename = GNUNET_strdup (filename);
- if (NULL != content_type)
- uc->content_type = GNUNET_strdup (content_type);
- }
- if (size > uc->buf_size - uc->buf_pos)
- {
- char *tmp;
- size_t tgt;
-
- tgt = uc->buf_size * 2;
- if (tgt >= GNUNET_MAX_MALLOC_CHECKED - 1)
- tgt = GNUNET_MAX_MALLOC_CHECKED - 1;
- if (tgt < size + uc->buf_pos)
- tgt = size + uc->buf_pos;
- if (tgt >= GNUNET_MAX_MALLOC_CHECKED - 1)
- return MHD_NO;
- tmp = GNUNET_malloc (tgt + 1); /* for 0-termination */
- memcpy (tmp,
- uc->curr_buf,
- uc->buf_pos);
- GNUNET_free (uc->curr_buf);
- uc->buf_size = tgt;
- uc->curr_buf = tmp;
- }
- memcpy (uc->curr_buf + uc->buf_pos,
- data,
- size);
- uc->buf_pos += size;
- return MHD_YES;
-}
-
-
-/**
* Function called after the KYC-AML trigger is done.
*
* @param cls closure
@@ -380,11 +184,11 @@ aml_trigger_callback (
MHD_RESULT
TEH_handler_kyc_upload (
struct TEH_RequestContext *rc,
- const char *id,
- size_t *upload_data_size,
- const char *upload_data)
+ const json_t *root,
+ const char *const args[1])
{
struct UploadContext *uc = rc->rh_ctx;
+ const char *id = args[0];
if (NULL == uc)
{
@@ -393,26 +197,9 @@ TEH_handler_kyc_upload (
uc = GNUNET_new (struct UploadContext);
uc->rc = rc;
- uc->pp = MHD_create_post_processor (
- rc->connection,
- UPLOAD_BUFFER_SIZE,
- &post_helper,
- uc);
- if (NULL == uc->pp)
- {
- GNUNET_break (0);
- GNUNET_free (uc);
- return TALER_MHD_reply_with_error (
- rc->connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_ALLOCATION_FAILURE,
- "MHD_create_post_processor");
- }
- uc->result = json_object ();
- GNUNET_assert (NULL != uc->result);
+ uc->result = root;
rc->rh_ctx = uc;
rc->rh_cleaner = &upload_cleaner;
-
slash = strchr (id, '-');
if (NULL == slash)
{
@@ -459,18 +246,6 @@ TEH_handler_kyc_upload (
uc->response);
}
- if (0 != *upload_data_size)
- {
- MHD_RESULT mres;
-
- mres = MHD_post_process (uc->pp,
- upload_data,
- *upload_data_size);
- *upload_data_size = 0;
- return mres;
- }
- finish_key (uc);
- GNUNET_assert (NULL == uc->kat);
{
uint64_t legi_process_row;
diff --git a/src/exchange/taler-exchange-httpd_kyc-upload.h b/src/exchange/taler-exchange-httpd_kyc-upload.h
@@ -40,17 +40,14 @@ TEH_kyc_upload_cleanup (void);
* Handle a "/kyc-upload/$ID" request.
*
* @param rc request context
- * @param id the ID from the URL (without "/")
- * @param[in,out] upload_data_size length of @a upload_data,
- * to be update to reflect number of bytes remaining
- * @param upload_data upload data of the POST, if any
+ * @param root json body being uploaded
+ * @param args includes the ID from the URL (without "/")
* @return MHD result code
*/
MHD_RESULT
TEH_handler_kyc_upload (struct TEH_RequestContext *rc,
- const char *id,
- size_t *upload_data_size,
- const char *upload_data);
+ const json_t *root,
+ const char *const args[1]);
#endif
diff --git a/src/testing/test_kyc_api.c b/src/testing/test_kyc_api.c
@@ -770,8 +770,8 @@ run (void *cls,
"wallet-post-kyc-form",
"get-kyc-info-form",
0, /* requirement index */
- "application/x-www-form-urlencoded",
- "full_name=Bob&birthdate=1990-00-00",
+ "application/json",
+ "{\"full_name\":\"Bob\",\"birthdate\":\"1990-00-00\"}",
MHD_HTTP_NO_CONTENT),
/* now this should be allowed */
TALER_TESTING_cmd_wallet_kyc_get (