diff options
Diffstat (limited to 'src/mhd/mhd_parsing.c')
-rw-r--r-- | src/mhd/mhd_parsing.c | 336 |
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 */ |