exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

commit 3ccbc5df54541169ee5e3f2b88d01928e713c741
parent 9e127fb00d1e530c307a8df48d9325cdb6c84459
Author: Christian Grothoff <christian@grothoff.org>
Date:   Sun, 29 Dec 2024 14:03:27 +0100

fix #9420 + #9428

Diffstat:
Msrc/include/taler_json_lib.h | 2+-
Msrc/include/taler_mhd_lib.h | 41++---------------------------------------
Msrc/include/taler_util.h | 12++++++------
Msrc/json/i18n.c | 4++--
Msrc/json/json_helper.c | 4++--
Msrc/mhd/Makefile.am | 2+-
Msrc/mhd/mhd_legal.c | 125++++++++++++++++++++++++-------------------------------------------------------
Msrc/mhd/mhd_parsing.c | 62--------------------------------------------------------------
Msrc/templating/templating_api.c | 17+++++++++++------
Msrc/util/Makefile.am | 2+-
Msrc/util/lang.c | 58++++++++++++++++++++++++++++++++++++++++++----------------
11 files changed, 105 insertions(+), 224 deletions(-)

diff --git a/src/include/taler_json_lib.h b/src/include/taler_json_lib.h @@ -645,7 +645,7 @@ TALER_JSON_spec_blinded_planchet ( * * The @a language_pattern is given using the format from * https://tools.ietf.org/html/rfc7231#section-5.3.1 - * so that #TALER_language_matches() can be used. + * so that #TALER_pattern_matches() can be used. * * @param name name of the JSON field * @param language_pattern language pattern to use to find best match, possibly NULL diff --git a/src/include/taler_mhd_lib.h b/src/include/taler_mhd_lib.h @@ -104,20 +104,6 @@ TALER_MHD_can_compress (struct MHD_Connection *connection); /** - * Check if @a mime matches the @a accept_pattern. For this function, the @a - * accept_pattern may include multiple values separated by ";". - * - * @param accept_pattern a mime pattern like "text/plain" - * or "image/STAR" or "text/plain; text/xml" - * @param mime the mime type to match - * @return true if @a mime matches the @a accept_pattern - */ -bool -TALER_MHD_xmime_matches (const char *accept_pattern, - const char *mime); - - -/** * Send JSON object as response. * * @param connection the MHD connection @@ -651,9 +637,8 @@ TALER_MHD_parse_request_arg_amount (struct MHD_Connection *connection, /** - * Extract optional amount argument from request. - * Macro that *returns* #MHD_YES/#MHD_NO if the - * requested argument existed but failed to parse. + * Extract optional amount argument from request. Macro that *returns* + * #MHD_YES/#MHD_NO if the requested argument existed but failed to parse. * * @param connection the MHD connection * @param name name of the argument to parse @@ -678,28 +663,6 @@ TALER_MHD_parse_request_arg_amount (struct MHD_Connection *connection, /** - * Determines which of the given choices is preferred - * by the client. Parses an HTTP header such as - * "Accept:" or "Language:" to find entries matching - * the list of strings given in the variadic argument - * list. Returns the index of the preferred choice. - * - * @param connection HTTP request handle - * @param header type of HTTP header to evaluate - * @param ... NULL-terminated list of choices to - * check for in the header - * @return -1 if none of the given choices is in - * the header, -2 if the header is missing, - * otherwise index of preferred choice in - * the varargs list - */ -int -TALER_MHD_check_accept (struct MHD_Connection *connection, - const char *header, - ...); - - -/** * Extract fixed-size base32crockford encoded data from request argument. * * Queues an error response to the connection if the parameter is missing or diff --git a/src/include/taler_util.h b/src/include/taler_util.h @@ -441,15 +441,15 @@ TALER_is_web_url (const char *url); * which preference. * See also: https://tools.ietf.org/html/rfc7231#section-5.3.1 * - * @param language_pattern a language preferences string + * @param pattern a preferences string * like "fr-CH, fr;q=0.9, en;q=0.8, *;q=0.1" - * @param lang the 2-digit language to match - * @return q-weight given for @a lang in @a language_pattern, 1.0 if no weights are given; - * 0 if @a lang is not in @a language_pattern + * @param value the value to match + * @return q-weight given for @a value in @a pattern, 1.0 if no weights are given; + * 0 if @a value is not in @a pattern */ double -TALER_language_matches (const char *language_pattern, - const char *lang); +TALER_pattern_matches (const char *pattern, + const char *value); /** diff --git a/src/json/i18n.c b/src/json/i18n.c @@ -54,8 +54,8 @@ TALER_JSON_extract_i18n (const json_t *object, json_t *value; json_object_foreach (i18n, key, value) { - double q = TALER_language_matches (language_pattern, - key); + double q = TALER_pattern_matches (language_pattern, + key); if (q > quality) { quality = q; diff --git a/src/json/json_helper.c b/src/json/json_helper.c @@ -1129,8 +1129,8 @@ parse_i18n_string (void *cls, { double score; - score = TALER_language_matches (ctx->lp, - lang); + score = TALER_pattern_matches (ctx->lp, + lang); if (score > best) { best = score; diff --git a/src/mhd/Makefile.am b/src/mhd/Makefile.am @@ -17,7 +17,7 @@ libtalermhd_la_SOURCES = \ mhd_run.c \ mhd_spa.c libtalermhd_la_LDFLAGS = \ - -version-info 4:0:4 \ + -version-info 5:0:0 \ -no-undefined libtalermhd_la_LIBADD = \ $(top_builddir)/src/json/libtalerjson.la \ diff --git a/src/mhd/mhd_legal.c b/src/mhd/mhd_legal.c @@ -121,69 +121,6 @@ struct TALER_MHD_Legal }; -/** - * Check if @a mime matches the @a accept_pattern. - * - * @param accept_pattern a mime pattern like "text/plain" - * or "image/STAR" - * @param mime the mime type to match - * @return true if @a mime matches the @a accept_pattern - */ -static bool -mime_matches (const char *accept_pattern, - const char *mime) -{ - const char *da = strchr (accept_pattern, '/'); - const char *dm = strchr (mime, '/'); - const char *end; - - if ( (NULL == da) || - (NULL == dm) ) - return (0 == strcmp ("*", accept_pattern)); - // FIXME-#9428: use TALER_MHD_check_accept() here! - /* FIXME-#9420: 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 (da, ';'); - if (NULL == end) - end = &da[strlen (da)]; - return - ( ( (1 == da - accept_pattern) && - ('*' == *accept_pattern) ) || - ( (da - accept_pattern == dm - mime) && - (0 == strncasecmp (accept_pattern, - mime, - da - accept_pattern)) ) ) && - ( (0 == strcmp (da, "/*")) || - (0 == strncasecmp (da, - dm, - end - da)) ); -} - - -bool -TALER_MHD_xmime_matches (const char *accept_pattern, - const char *mime) -{ - char *ap = GNUNET_strdup (accept_pattern); - char *sptr; - - for (const char *tok = strtok_r (ap, ",", &sptr); - NULL != tok; - tok = strtok_r (NULL, ",", &sptr)) - { - if (mime_matches (tok, - mime)) - { - GNUNET_free (ap); - return true; - } - } - GNUNET_free (ap); - return false; -} - - MHD_RESULT TALER_MHD_reply_legal (struct MHD_Connection *conn, struct TALER_MHD_Legal *legal) @@ -229,6 +166,8 @@ TALER_MHD_reply_legal (struct MHD_Connection *conn, { const char *mime; const char *lang; + double best_mime_q = 0.0; + double best_lang_q = 0.0; mime = MHD_lookup_connection_value (conn, MHD_HEADER_KIND, @@ -246,34 +185,44 @@ TALER_MHD_reply_legal (struct MHD_Connection *conn, NULL != p; p = p->next) { - if ( (NULL == t) || - (TALER_MHD_xmime_matches (mime, - p->mime_type)) ) + double q; + + q = TALER_pattern_matches (mime, + p->mime_type); + if (q > best_mime_q) + best_mime_q = q; + } + for (struct Terms *p = legal->terms_head; + NULL != p; + p = p->next) + { + double q; + + q = TALER_pattern_matches (mime, + p->mime_type); + if (q < best_mime_q) + continue; + if (NULL == langs) { - if (NULL == langs) - { - langs = GNUNET_strdup (p->language); - } - else if (NULL == strstr (langs, - p->language)) - { - char *tmp = langs; + langs = GNUNET_strdup (p->language); + } + else if (NULL == strstr (langs, + p->language)) + { + char *tmp = langs; - GNUNET_asprintf (&langs, - "%s,%s", - tmp, - p->language); - GNUNET_free (tmp); - } - if ( (NULL == t) || - (! TALER_MHD_xmime_matches (mime, - t->mime_type)) || - (TALER_language_matches (lang, - p->language) > - TALER_language_matches (lang, - t->language) ) ) - t = p; + GNUNET_asprintf (&langs, + "%s,%s", + tmp, + p->language); + GNUNET_free (tmp); } + q = TALER_pattern_matches (langs, + p->language); + if (q < best_lang_q) + continue; + best_lang_q = q; + t = p; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Best match for %s/%s: %s / %s\n", diff --git a/src/mhd/mhd_parsing.c b/src/mhd/mhd_parsing.c @@ -556,66 +556,4 @@ TALER_MHD_check_content_length_ (struct MHD_Connection *connection, } -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-#9420: 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 */ diff --git a/src/templating/templating_api.c b/src/templating/templating_api.c @@ -77,6 +77,7 @@ lookup_template (struct MHD_Connection *connection, const char *name) { struct TVE *best = NULL; + double best_q = 0.0; const char *lang; lang = MHD_lookup_connection_value (connection, @@ -87,15 +88,19 @@ lookup_template (struct MHD_Connection *connection, /* find best match by language */ for (unsigned int i = 0; i<loaded_length; i++) { + double q; + if (0 != strcmp (loaded[i].name, name)) continue; /* does not match by name */ - if ( (NULL == best) || - (TALER_language_matches (lang, - loaded[i].lang) > - TALER_language_matches (lang, - best->lang) ) ) - best = &loaded[i]; + if (NULL == loaded[i].lang) /* no language == always best match */ + return loaded[i].value; + q = TALER_pattern_matches (lang, + loaded[i].lang); + if (q < best_q) + continue; + best_q = q; + best = &loaded[i]; } if (NULL == best) { diff --git a/src/util/Makefile.am b/src/util/Makefile.am @@ -127,7 +127,7 @@ libtalerutil_la_LIBADD = \ -lm libtalerutil_la_LDFLAGS = \ - -version-info 6:0:1 \ + -version-info 7:0:0 \ -no-undefined diff --git a/src/util/lang.c b/src/util/lang.c @@ -21,23 +21,50 @@ #include "platform.h" #include "taler_util.h" - /** - * Check if @a lang matches the @a language_pattern, and if so with - * which preference. - * See also: https://tools.ietf.org/html/rfc7231#section-5.3.1 + * Check if @a value matches the @a accept_pattern. * - * @param language_pattern a language preferences string - * like "fr-CH, fr;q=0.9, en;q=0.8, *;q=0.1" - * @param lang the 2-digit language to match - * @return q-weight given for @a lang in @a language_pattern, 1.0 if no weights are given; - * 0 if @a lang is not in @a language_pattern + * @param accept_pattern a pattern like "[text|STAR/]*[text|STAR]" + * @param value the value to match + * @return true if @a value matches the @a accept_pattern */ +static bool +pattern_matches (const char *accept_pattern, + const char *value) +{ + const char *da; + const char *dm; + + if (0 == strcmp ("*", + accept_pattern)) + return true; + if (0 == strcmp (value, + accept_pattern)) + return true; + da = strchr (accept_pattern, + '/'); + dm = strchr (value, + '/'); + if ( (NULL == da) || + (NULL == dm) ) + return false; + if ( ( (1 == da - accept_pattern) && + ('*' == *accept_pattern) ) || + ( (da - accept_pattern == dm - value) && + (0 == strncasecmp (accept_pattern, + value, + da - accept_pattern)) ) ) + return pattern_matches (da + 1, + dm + 1); + return false; +} + + double -TALER_language_matches (const char *language_pattern, - const char *lang) +TALER_pattern_matches (const char *pattern, + const char *value) { - char *p = GNUNET_strdup (language_pattern); + char *p = GNUNET_strdup (pattern); char *sptr; double r = 0.0; @@ -50,8 +77,7 @@ TALER_language_matches (const char *language_pattern, char *qp = strtok_r (NULL, ";", &sptr2); double q = 1.0; - if (NULL == lp) - continue; /* should be impossible, but makes static analysis happy */ + GNUNET_assert (NULL != lp); while (isspace ((int) *lp)) lp++; if (NULL != qp) @@ -61,8 +87,8 @@ TALER_language_matches (const char *language_pattern, (1 == sscanf (qp, "q=%lf", &q)) ); - if (0 == strcasecmp (lang, - lp)) + if (pattern_matches (lp, + value)) r = GNUNET_MAX (r, q); } GNUNET_free (p);