summaryrefslogtreecommitdiff
path: root/src/mhd/mhd_parsing.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mhd/mhd_parsing.c')
-rw-r--r--src/mhd/mhd_parsing.c336
1 files changed, 322 insertions, 14 deletions
diff --git a/src/mhd/mhd_parsing.c b/src/mhd/mhd_parsing.c
index bae10e724..771319bd5 100644
--- a/src/mhd/mhd_parsing.c
+++ b/src/mhd/mhd_parsing.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014--2020 Taler Systems SA
+ Copyright (C) 2014--2024 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
@@ -60,7 +60,7 @@ TALER_MHD_parse_post_json (struct MHD_Connection *connection,
GNUNET_break (NULL == *json);
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Closing connection, upload too large\n");
- return MHD_NO;
+ return GNUNET_SYSERR;
case GNUNET_JSON_PR_JSON_INVALID:
GNUNET_break (NULL == *json);
return (MHD_YES ==
@@ -86,25 +86,40 @@ TALER_MHD_parse_post_cleanup_callback (void *con_cls)
}
-enum GNUNET_GenericReturnValue
-TALER_MHD_parse_request_arg_data (struct MHD_Connection *connection,
- const char *param_name,
- void *out_data,
- size_t out_size)
+/**
+ * Extract 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 HTTP key with the value
+ * @param kind whether to extract from header, argument or footer
+ * @param[out] out_data pointer to store the result
+ * @param out_size expected size of @a out_data
+ * @param[out] present set to true if argument was found
+ * @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)
+ */
+static enum GNUNET_GenericReturnValue
+parse_request_data (struct MHD_Connection *connection,
+ const char *param_name,
+ enum MHD_ValueKind kind,
+ void *out_data,
+ size_t out_size,
+ bool *present)
{
const char *str;
str = MHD_lookup_connection_value (connection,
- MHD_GET_ARGUMENT_KIND,
+ kind,
param_name);
if (NULL == str)
{
- return (MHD_NO ==
- TALER_MHD_reply_with_error (connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_GENERIC_PARAMETER_MISSING,
- param_name))
- ? GNUNET_SYSERR : GNUNET_NO;
+ *present = false;
+ return GNUNET_OK;
}
if (GNUNET_OK !=
GNUNET_STRINGS_string_to_data (str,
@@ -117,6 +132,182 @@ TALER_MHD_parse_request_arg_data (struct MHD_Connection *connection,
TALER_EC_GENERIC_PARAMETER_MALFORMED,
param_name))
? GNUNET_SYSERR : GNUNET_NO;
+ *present = true;
+ return GNUNET_OK;
+}
+
+
+enum GNUNET_GenericReturnValue
+TALER_MHD_parse_request_arg_data (struct MHD_Connection *connection,
+ const char *param_name,
+ void *out_data,
+ size_t out_size,
+ bool *present)
+{
+ return parse_request_data (connection,
+ param_name,
+ MHD_GET_ARGUMENT_KIND,
+ out_data,
+ out_size,
+ present);
+}
+
+
+enum GNUNET_GenericReturnValue
+TALER_MHD_parse_request_header_data (struct MHD_Connection *connection,
+ const char *header_name,
+ void *out_data,
+ size_t out_size,
+ bool *present)
+{
+ return parse_request_data (connection,
+ header_name,
+ MHD_HEADER_KIND,
+ out_data,
+ out_size,
+ present);
+}
+
+
+enum GNUNET_GenericReturnValue
+TALER_MHD_parse_request_arg_timeout (struct MHD_Connection *connection,
+ struct GNUNET_TIME_Absolute *expiration)
+{
+ const char *ts;
+ char dummy;
+ unsigned long long tms;
+
+ ts = MHD_lookup_connection_value (connection,
+ MHD_GET_ARGUMENT_KIND,
+ "timeout_ms");
+ if (NULL == ts)
+ {
+ *expiration = GNUNET_TIME_UNIT_ZERO_ABS;
+ return GNUNET_OK;
+ }
+ if (1 !=
+ sscanf (ts,
+ "%llu%c",
+ &tms,
+ &dummy))
+ {
+ MHD_RESULT mret;
+
+ GNUNET_break_op (0);
+ mret = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ "timeout_ms");
+ return (MHD_YES == mret)
+ ? GNUNET_NO
+ : GNUNET_SYSERR;
+ }
+ *expiration = GNUNET_TIME_relative_to_absolute (
+ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
+ tms));
+ return GNUNET_OK;
+}
+
+
+enum GNUNET_GenericReturnValue
+TALER_MHD_parse_request_arg_number (struct MHD_Connection *connection,
+ const char *name,
+ uint64_t *off)
+{
+ const char *ts;
+ char dummy;
+ unsigned long long num;
+
+ ts = MHD_lookup_connection_value (connection,
+ MHD_GET_ARGUMENT_KIND,
+ name);
+ if (NULL == ts)
+ return GNUNET_OK;
+ if (1 !=
+ sscanf (ts,
+ "%llu%c",
+ &num,
+ &dummy))
+ {
+ MHD_RESULT mret;
+
+ GNUNET_break_op (0);
+ mret = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ name);
+ return (MHD_YES == mret)
+ ? GNUNET_NO
+ : GNUNET_SYSERR;
+ }
+ *off = (uint64_t) num;
+ return GNUNET_OK;
+}
+
+
+enum GNUNET_GenericReturnValue
+TALER_MHD_parse_request_arg_snumber (struct MHD_Connection *connection,
+ const char *name,
+ int64_t *val)
+{
+ const char *ts;
+ char dummy;
+ long long num;
+
+ ts = MHD_lookup_connection_value (connection,
+ MHD_GET_ARGUMENT_KIND,
+ name);
+ if (NULL == ts)
+ return GNUNET_OK;
+ if (1 !=
+ sscanf (ts,
+ "%lld%c",
+ &num,
+ &dummy))
+ {
+ MHD_RESULT mret;
+
+ GNUNET_break_op (0);
+ mret = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ name);
+ return (MHD_YES == mret)
+ ? GNUNET_NO
+ : GNUNET_SYSERR;
+ }
+ *val = (int64_t) num;
+ return GNUNET_OK;
+}
+
+
+enum GNUNET_GenericReturnValue
+TALER_MHD_parse_request_arg_amount (struct MHD_Connection *connection,
+ const char *name,
+ struct TALER_Amount *val)
+{
+ const char *ts;
+
+ ts = MHD_lookup_connection_value (connection,
+ MHD_GET_ARGUMENT_KIND,
+ name);
+ if (NULL == ts)
+ return GNUNET_OK;
+ if (GNUNET_OK !=
+ TALER_string_to_amount (ts,
+ val))
+ {
+ MHD_RESULT mret;
+
+ GNUNET_break_op (0);
+ mret = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ name);
+ return (MHD_YES == mret)
+ ? GNUNET_NO
+ : GNUNET_SYSERR;
+ }
return GNUNET_OK;
}
@@ -262,4 +453,121 @@ TALER_MHD_parse_json_array (struct MHD_Connection *connection,
}
+enum GNUNET_GenericReturnValue
+TALER_MHD_check_content_length_ (struct MHD_Connection *connection,
+ unsigned long long max_len)
+{
+ const char *cl;
+ unsigned long long cv;
+ char dummy;
+
+ /* Maybe check for maximum upload size
+ and refuse requests if they are just too big. */
+ cl = MHD_lookup_connection_value (connection,
+ MHD_HEADER_KIND,
+ MHD_HTTP_HEADER_CONTENT_LENGTH);
+ if (NULL == cl)
+ {
+ return GNUNET_OK;
+#if 0
+ /* wallet currently doesn't always send content-length! */
+ GNUNET_break_op (0);
+ return (MHD_YES ==
+ TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_PARAMETER_MISSING,
+ MHD_HTTP_HEADER_CONTENT_LENGTH))
+ ? GNUNET_NO
+ : GNUNET_SYSERR;
+#endif
+ }
+ if (1 != sscanf (cl,
+ "%llu%c",
+ &cv,
+ &dummy))
+ {
+ /* Not valid HTTP request, just close connection. */
+ GNUNET_break_op (0);
+ return (MHD_YES ==
+ TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ MHD_HTTP_HEADER_CONTENT_LENGTH))
+ ? GNUNET_NO
+ : GNUNET_SYSERR;
+ }
+ if (cv > TALER_MHD_REQUEST_BUFFER_MAX)
+ {
+ GNUNET_break_op (0);
+ return (MHD_YES ==
+ TALER_MHD_reply_request_too_large (connection))
+ ? GNUNET_NO
+ : GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+int
+TALER_MHD_check_accept (struct MHD_Connection *connection,
+ const char *header,
+ ...)
+{
+ bool ret = false;
+ const char *accept;
+ char *a;
+ char *saveptr;
+
+ accept = MHD_lookup_connection_value (connection,
+ MHD_HEADER_KIND,
+ header);
+ if (NULL == accept)
+ return -2; /* no Accept header set */
+
+ a = GNUNET_strdup (accept);
+ for (char *t = strtok_r (a, ",", &saveptr);
+ NULL != t;
+ t = strtok_r (NULL, ",", &saveptr))
+ {
+ char *end;
+
+ /* skip leading whitespace */
+ while (isspace ((unsigned char) t[0]))
+ t++;
+ /* trim of ';q=' parameter and everything after space */
+ /* FIXME: eventually, we might want to parse the "q=$FLOAT"
+ part after the ';' and figure out which one is the
+ best/preferred match instead of returning a boolean... */
+ end = strchr (t, ';');
+ if (NULL != end)
+ *end = '\0';
+ end = strchr (t, ' ');
+ if (NULL != end)
+ *end = '\0';
+ {
+ va_list ap;
+ int off = 0;
+ const char *val;
+
+ va_start (ap,
+ header);
+ while (NULL != (val = va_arg (ap,
+ const char *)))
+ {
+ if (0 == strcasecmp (val,
+ t))
+ {
+ ret = off;
+ break;
+ }
+ off++;
+ }
+ va_end (ap);
+ }
+ }
+ GNUNET_free (a);
+ return ret;
+}
+
+
/* end of mhd_parsing.c */