gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-exchange] branch master updated: add parsing API to new libtalerm


From: gnunet
Subject: [taler-exchange] branch master updated: add parsing API to new libtalermhd
Date: Sat, 23 Nov 2019 11:02:36 +0100

This is an automated email from the git hooks/post-receive script.

grothoff pushed a commit to branch master
in repository exchange.

The following commit(s) were added to refs/heads/master by this push:
     new fef8a57f add parsing API to new libtalermhd
fef8a57f is described below

commit fef8a57fae513259fd0b08e430b04d3b59d20210
Author: Christian Grothoff <address@hidden>
AuthorDate: Sat Nov 23 11:02:34 2019 +0100

    add parsing API to new libtalermhd
---
 src/include/taler_mhd_lib.h | 108 ++++++++++++++++
 src/mhd/Makefile.am         |   3 +-
 src/mhd/mhd_parsing.c       | 294 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 404 insertions(+), 1 deletion(-)

diff --git a/src/include/taler_mhd_lib.h b/src/include/taler_mhd_lib.h
index 55396090..d126d0ae 100644
--- a/src/include/taler_mhd_lib.h
+++ b/src/include/taler_mhd_lib.h
@@ -24,6 +24,7 @@
 #ifndef TALER_MHD_LIB_H
 #define TALER_MHD_LIB_H
 #include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_json_lib.h>
 #include <jansson.h>
 #include <microhttpd.h>
 #include "taler_error_codes.h"
@@ -153,4 +154,111 @@ int
 TALER_MHD_reply_request_too_large (struct MHD_Connection *connection);
 
 
+/**
+ * Process a POST request containing a JSON object.  This
+ * function realizes an MHD POST processor that will
+ * (incrementally) process JSON data uploaded to the HTTP
+ * server.  It will store the required state in the
+ * "connection_cls", which must be cleaned up using
+ * #TALER_MHD_post_cleanup_callback().
+ *
+ * @param connection the MHD connection
+ * @param con_cls the closure (points to a `struct Buffer *`)
+ * @param upload_data the POST data
+ * @param upload_data_size number of bytes in @a upload_data
+ * @param json the JSON object for a completed request
+ * @return
+ *    #GNUNET_YES if json object was parsed or at least
+ *               may be parsed in the future (call again);
+ *               `*json` will be NULL if we need to be called again,
+ *                and non-NULL if we are done.
+ *    #GNUNET_NO is request incomplete or invalid
+ *               (error message was generated)
+ *    #GNUNET_SYSERR on internal error
+ *               (we could not even queue an error message,
+ *                close HTTP session with MHD_NO)
+ */
+int
+TALER_MHD_parse_post_json (struct MHD_Connection *connection,
+                           void **con_cls,
+                           const char *upload_data,
+                           size_t *upload_data_size,
+                           json_t **json);
+
+
+/**
+ * Function called whenever we are done with a request
+ * to clean up our state.
+ *
+ * @param con_cls value as it was left by
+ *        #TALER_MHD_post_json(), to be cleaned up
+ */
+void
+TALER_MHD_parse_post_cleanup_callback (void *con_cls);
+
+
+/**
+ * Parse JSON object into components based on the given field
+ * specification.
+ *
+ * @param connection the connection to send an error response to
+ * @param root the JSON node to start the navigation at.
+ * @param spec field specification for the parser
+ * @return
+ *    #GNUNET_YES if navigation was successful (caller is responsible
+ *                for freeing allocated variable-size data using
+ *                GNUNET_JSON_parse_free() when done)
+ *    #GNUNET_NO if json is malformed, error response was generated
+ *    #GNUNET_SYSERR on internal error
+ */
+int
+TALER_MHD_parse_json_data (struct MHD_Connection *connection,
+                           const json_t *root,
+                           struct GNUNET_JSON_Specification *spec);
+
+
+/**
+ * Parse JSON array into components based on the given field
+ * specification.  Generates error response on parse errors.
+ *
+ * @param connection the connection to send an error response to
+ * @param root the JSON node to start the navigation at.
+ * @param[in,out] spec field specification for the parser
+ * @param ... -1-terminated list of array offsets of type 'int'
+ * @return
+ *    #GNUNET_YES if navigation was successful (caller is responsible
+ *                for freeing allocated variable-size data using
+ *                GNUNET_JSON_parse_free() when done)
+ *    #GNUNET_NO if json is malformed, error response was generated
+ *    #GNUNET_SYSERR on internal error
+ */
+int
+TALER_MHD_parse_json_array (struct MHD_Connection *connection,
+                            const json_t *root,
+                            struct GNUNET_JSON_Specification *spec,
+                            ...);
+
+
+/**
+ * Extraxt fixed-size base32crockford encoded data from request.
+ *
+ * Queues an error response to the connection if the parameter is missing or
+ * invalid.
+ *
+ * @param connection the MHD connection
+ * @param param_name the name of the parameter with the key
+ * @param[out] out_data pointer to store the result
+ * @param out_size expected size of @a out_data
+ * @return
+ *   #GNUNET_YES if the the argument is present
+ *   #GNUNET_NO if the argument is absent or malformed
+ *   #GNUNET_SYSERR on internal error (error response could not be sent)
+ */
+int
+TALER_MHD_parse_request_arg_data (struct MHD_Connection *connection,
+                                  const char *param_name,
+                                  void *out_data,
+                                  size_t out_size);
+
+
 #endif
diff --git a/src/mhd/Makefile.am b/src/mhd/Makefile.am
index 2c6d464f..ed0c8841 100644
--- a/src/mhd/Makefile.am
+++ b/src/mhd/Makefile.am
@@ -10,7 +10,8 @@ lib_LTLIBRARIES = \
   libtalermhd.la
 
 libtalermhd_la_SOURCES = \
-  mhd_responses.c
+  mhd_parsing.c \
+  mhd_responses.c 
 libtalermhd_la_LDFLAGS = \
   -version-info 0:0:0 \
   -export-dynamic -no-undefined
diff --git a/src/mhd/mhd_parsing.c b/src/mhd/mhd_parsing.c
new file mode 100644
index 00000000..0b070ffe
--- /dev/null
+++ b/src/mhd/mhd_parsing.c
@@ -0,0 +1,294 @@
+/*
+  This file is part of TALER
+  Copyright (C) 2014--2019 Taler Systems SA
+
+  TALER is free software; you can redistribute it and/or modify it under the
+  terms of the GNU Affero General Public License as published by the Free 
Software
+  Foundation; either version 3, or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more 
details.
+
+  You should have received a copy of the GNU Affero General Public License 
along with
+  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file mhd_parsing.c
+ * @brief functions to parse incoming requests (MHD arguments and JSON 
snippets)
+ * @author Florian Dold
+ * @author Benedikt Mueller
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_json_lib.h>
+#include "taler_json_lib.h"
+#include "taler_mhd_lib.h"
+
+
+/**
+ * Maximum POST request size.
+ */
+#define REQUEST_BUFFER_MAX (1024 * 1024)
+
+
+/**
+ * Process a POST request containing a JSON object.  This function
+ * realizes an MHD POST processor that will (incrementally) process
+ * JSON data uploaded to the HTTP server.  It will store the required
+ * state in the @a con_cls, which must be cleaned up using
+ * #TALER_MHD_post_cleanup_callback().
+ *
+ * @param connection the MHD connection
+ * @param con_cls the closure (points to a `struct Buffer *`)
+ * @param upload_data the POST data
+ * @param upload_data_size number of bytes in @a upload_data
+ * @param json the JSON object for a completed request
+ * @return
+ *    #GNUNET_YES if json object was parsed or at least
+ *               may be parsed in the future (call again);
+ *               `*json` will be NULL if we need to be called again,
+ *                and non-NULL if we are done.
+ *    #GNUNET_NO is request incomplete or invalid
+ *               (error message was generated)
+ *    #GNUNET_SYSERR on internal error
+ *               (we could not even queue an error message,
+ *                close HTTP session with MHD_NO)
+ */
+int
+TALER_MHD_parse_post_json (struct MHD_Connection *connection,
+                           void **con_cls,
+                           const char *upload_data,
+                           size_t *upload_data_size,
+                           json_t **json)
+{
+  enum GNUNET_JSON_PostResult pr;
+
+  pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX,
+                                connection,
+                                con_cls,
+                                upload_data,
+                                upload_data_size,
+                                json);
+  switch (pr)
+  {
+  case GNUNET_JSON_PR_OUT_OF_MEMORY:
+    return (MHD_NO ==
+            TALER_MHD_reply_with_error
+              (connection,
+              MHD_HTTP_INTERNAL_SERVER_ERROR,
+              TALER_EC_PARSER_OUT_OF_MEMORY,
+              "out of memory")) ? GNUNET_SYSERR : GNUNET_NO;
+
+  case GNUNET_JSON_PR_CONTINUE:
+    return GNUNET_YES;
+  case GNUNET_JSON_PR_REQUEST_TOO_LARGE:
+    return (MHD_NO ==
+            TALER_MHD_reply_request_too_large
+              (connection)) ? GNUNET_SYSERR : GNUNET_NO;
+  case GNUNET_JSON_PR_JSON_INVALID:
+    return (MHD_YES ==
+            TALER_MHD_reply_with_error (connection,
+                                        MHD_HTTP_BAD_REQUEST,
+                                        TALER_EC_JSON_INVALID,
+                                        "invalid JSON uploaded"))
+           ? GNUNET_NO : GNUNET_SYSERR;
+  case GNUNET_JSON_PR_SUCCESS:
+    GNUNET_break (NULL != *json);
+    return GNUNET_YES;
+  }
+  /* this should never happen */
+  GNUNET_break (0);
+  return GNUNET_SYSERR;
+}
+
+
+/**
+ * Function called whenever we are done with a request
+ * to clean up our state.
+ *
+ * @param con_cls value as it was left by
+ *        #TALER_MHD_post_json(), to be cleaned up
+ */
+void
+TALER_MHD_parse_post_cleanup_callback (void *con_cls)
+{
+  // FIXME: this should probably NOT be done with a 'void *' like this!
+  GNUNET_JSON_post_parser_cleanup (con_cls);
+}
+
+
+/**
+ * Extract base32crockford encoded data from request.
+ *
+ * Queues an error response to the connection if the parameter is
+ * missing or invalid.
+ *
+ * @param connection the MHD connection
+ * @param param_name the name of the parameter with the key
+ * @param[out] out_data pointer to store the result
+ * @param out_size expected size of data
+ * @return
+ *   #GNUNET_YES if the the argument is present
+ *   #GNUNET_NO if the argument is absent or malformed
+ *   #GNUNET_SYSERR on internal error (error response could not be sent)
+ */
+int
+TALER_MHD_parse_request_arg_data (struct MHD_Connection *connection,
+                                  const char *param_name,
+                                  void *out_data,
+                                  size_t out_size)
+{
+  const char *str;
+
+  str = MHD_lookup_connection_value (connection,
+                                     MHD_GET_ARGUMENT_KIND,
+                                     param_name);
+  if (NULL == str)
+  {
+    return (MHD_NO ==
+            TALER_MHD_reply_with_error (connection,
+                                        MHD_HTTP_BAD_REQUEST,
+                                        TALER_EC_PARAMETER_MISSING,
+                                        param_name))
+           ? GNUNET_SYSERR : GNUNET_NO;
+  }
+  if (GNUNET_OK !=
+      GNUNET_STRINGS_string_to_data (str,
+                                     strlen (str),
+                                     out_data,
+                                     out_size))
+    return (MHD_NO ==
+            TALER_MHD_reply_with_error (connection,
+                                        MHD_HTTP_BAD_REQUEST,
+                                        TALER_EC_PARAMETER_MALFORMED,
+                                        param_name))
+           ? GNUNET_SYSERR : GNUNET_NO;
+  return GNUNET_OK;
+}
+
+
+/**
+ * Parse JSON object into components based on the given field
+ * specification.  Generates error response on parse errors.
+ *
+ * @param connection the connection to send an error response to
+ * @param root the JSON node to start the navigation at.
+ * @param[in,out] spec field specification for the parser
+ * @return
+ *    #GNUNET_YES if navigation was successful (caller is responsible
+ *                for freeing allocated variable-size data using
+ *                GNUNET_JSON_parse_free() when done)
+ *    #GNUNET_NO if json is malformed, error response was generated
+ *    #GNUNET_SYSERR on internal error
+ */
+int
+TALER_MHD_parse_json_data (struct MHD_Connection *connection,
+                           const json_t *root,
+                           struct GNUNET_JSON_Specification *spec)
+{
+  int ret;
+  const char *error_json_name;
+  unsigned int error_line;
+
+  ret = GNUNET_JSON_parse (root,
+                           spec,
+                           &error_json_name,
+                           &error_line);
+  if (GNUNET_SYSERR == ret)
+  {
+    if (NULL == error_json_name)
+      error_json_name = "<no field>";
+    ret = (MHD_YES ==
+           TALER_MHD_reply_json_pack (connection,
+                                      MHD_HTTP_BAD_REQUEST,
+                                      "{s:s, s:I, s:s, s:I}",
+                                      "hint", "JSON parse error",
+                                      "code",
+                                      (json_int_t)
+                                      TALER_EC_JSON_INVALID_WITH_DETAILS,
+                                      "field", error_json_name,
+                                      "line", (json_int_t) error_line))
+          ? GNUNET_NO : GNUNET_SYSERR;
+    return ret;
+  }
+  return GNUNET_YES;
+}
+
+
+/**
+ * Parse JSON array into components based on the given field
+ * specification.  Generates error response on parse errors.
+ *
+ * @param connection the connection to send an error response to
+ * @param root the JSON node to start the navigation at.
+ * @param[in,out] spec field specification for the parser
+ * @param ... -1-terminated list of array offsets of type 'int'
+ * @return
+ *    #GNUNET_YES if navigation was successful (caller is responsible
+ *                for freeing allocated variable-size data using
+ *                GNUNET_JSON_parse_free() when done)
+ *    #GNUNET_NO if json is malformed, error response was generated
+ *    #GNUNET_SYSERR on internal error
+ */
+int
+TALER_MHD_parse_json_array (struct MHD_Connection *connection,
+                            const json_t *root,
+                            struct GNUNET_JSON_Specification *spec,
+                            ...)
+{
+  int ret;
+  const char *error_json_name;
+  unsigned int error_line;
+  va_list ap;
+  json_int_t dim;
+
+  va_start (ap, spec);
+  dim = 0;
+  while ( (-1 != (ret = va_arg (ap, int))) &&
+          (NULL != root) )
+  {
+    dim++;
+    root = json_array_get (root, ret);
+  }
+  va_end (ap);
+  if (NULL == root)
+  {
+    ret = (MHD_YES ==
+           TALER_MHD_reply_json_pack (connection,
+                                      MHD_HTTP_BAD_REQUEST,
+                                      "{s:s, s:I, s:I}",
+                                      "hint", "expected array",
+                                      "code",
+                                      (json_int_t)
+                                      TALER_EC_JSON_INVALID_WITH_DETAILS,
+                                      "dimension", dim))
+          ? GNUNET_NO : GNUNET_SYSERR;
+    return ret;
+  }
+  ret = GNUNET_JSON_parse (root,
+                           spec,
+                           &error_json_name,
+                           &error_line);
+  if (GNUNET_SYSERR == ret)
+  {
+    if (NULL == error_json_name)
+      error_json_name = "<no field>";
+    ret = (MHD_YES ==
+           TALER_MHD_reply_json_pack (connection,
+                                      MHD_HTTP_BAD_REQUEST,
+                                      "{s:s, s:I, s:I}",
+                                      "hint", error_json_name,
+                                      "code",
+                                      (json_int_t)
+                                      TALER_EC_JSON_INVALID_WITH_DETAILS,
+                                      "line", (json_int_t) error_line))
+          ? GNUNET_NO : GNUNET_SYSERR;
+    return ret;
+  }
+  return GNUNET_YES;
+}
+
+
+/* end of mhd_parsing.c */

-- 
To stop receiving notification emails like this one, please contact
address@hidden.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]