diff options
author | Christian Grothoff <christian@grothoff.org> | 2021-04-01 12:07:48 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2021-04-01 12:09:58 +0200 |
commit | fb6d4b23a34436310b9646f14913ba1c4cd4b071 (patch) | |
tree | d1e1241069e48c9aa6cdf0c14d8899adf89e2f2e /src/backend | |
parent | 9b729aceb6e02c3a8ef7a8f0b010cd32263da33c (diff) | |
download | merchant-fb6d4b23a34436310b9646f14913ba1c4cd4b071.tar.gz merchant-fb6d4b23a34436310b9646f14913ba1c4cd4b071.tar.bz2 merchant-fb6d4b23a34436310b9646f14913ba1c4cd4b071.zip |
fix spec compliance for 405 reply, handle OPTIONS request with asterisk-form (RFC 7230, section 5.3.4)
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/taler-merchant-httpd.c | 184 |
1 files changed, 147 insertions, 37 deletions
diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c index a1727a3f..fdb752c9 100644 --- a/src/backend/taler-merchant-httpd.c +++ b/src/backend/taler-merchant-httpd.c @@ -963,6 +963,23 @@ TMH_add_instance (struct TMH_MerchantInstance *mi) /** + * Handle a OPTIONS "*" request. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] hc context with further information about the request + * @return MHD result code + */ +static MHD_RESULT +handle_server_options (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc) +{ + return TALER_MHD_reply_cors_preflight (connection); +} + + +/** * Extract the token from authorization header value @a auth. * * @param auth pointer to authorization header value, @@ -994,6 +1011,65 @@ extract_token (const char **auth) /** + * Checks if the @a rh matches the given (parsed) URL. + * + * @param rh handler to compare against + * @param url the main URL (without "/private/" prefix, if any) + * @param prefix_strlen length of the prefix, i.e. 8 for '/orders/' or 7 for '/config' + * @param infix_url infix text, i.e. "$ORDER_ID". + * @param infix_strlen length of the string in @a infix_url + * @param suffix_url suffix, i.e. "/refund", including the "/" + * @param suffix_strlen number of characters in @a suffix_url + * @return true if @a rh matches this request + */ +static bool +prefix_match (const struct TMH_RequestHandler *rh, + const char *url, + size_t prefix_strlen, + const char *infix_url, + size_t infix_strlen, + const char *suffix_url, + size_t suffix_strlen) +{ + if ( (prefix_strlen != strlen (rh->url_prefix)) || + (0 != memcmp (url, + rh->url_prefix, + prefix_strlen)) ) + return false; + if (! rh->have_id_segment) + { + if (NULL != suffix_url) + return false; /* too many segments to match */ + if ( (NULL == infix_url) + ^ (NULL == rh->url_suffix) ) + return false; /* suffix existence mismatch */ + if ( (NULL != infix_url) && + ( (infix_strlen != strlen (rh->url_suffix)) || + (0 != memcmp (infix_url, + rh->url_suffix, + infix_strlen)) ) ) + return false; /* cannot use infix as suffix: content mismatch */ + } + else + { + if ( (NULL == infix_url) + ^ (! rh->have_id_segment) ) // FIXME: have_id_segment is always 'true' here! + return false; /* infix existence mismatch */ + if ( ( (NULL == suffix_url) + ^ (NULL == rh->url_suffix) ) ) + return false; /* suffix existence mismatch */ + if ( (NULL != suffix_url) && + ( (suffix_strlen != strlen (rh->url_suffix)) || + (0 != memcmp (suffix_url, + rh->url_suffix, + suffix_strlen)) ) ) + return false; /* suffix content mismatch */ + } + return true; +} + + +/** * A client has requested the given url using the given method * (#MHD_HTTP_METHOD_GET, #MHD_HTTP_METHOD_PUT, * #MHD_HTTP_METHOD_DELETE, #MHD_HTTP_METHOD_POST, etc). The callback @@ -1451,6 +1527,11 @@ url_handler (void *cls, .handler = &TMH_return_static }, { + .url_prefix = "*", + .method = MHD_HTTP_METHOD_OPTIONS, + .handler = &handle_server_options + }, + { NULL } }; @@ -1658,40 +1739,14 @@ url_handler (void *cls, { struct TMH_RequestHandler *rh = &handlers[i]; - if ( (prefix_strlen != strlen (rh->url_prefix)) || - (0 != memcmp (url, - rh->url_prefix, - prefix_strlen)) ) + if (! prefix_match (rh, + url, + prefix_strlen, + infix_url, + infix_strlen, + suffix_url, + suffix_strlen)) continue; - if (! rh->have_id_segment) - { - if (NULL != suffix_url) - continue; /* too many segments to match */ - if ( (NULL == infix_url) - ^ (NULL == rh->url_suffix) ) - continue; /* suffix existence mismatch */ - if ( (NULL != infix_url) && - ( (infix_strlen != strlen (rh->url_suffix)) || - (0 != memcmp (infix_url, - rh->url_suffix, - infix_strlen)) ) ) - continue; /* cannot use infix as suffix: content mismatch */ - } - else - { - if ( (NULL == infix_url) - ^ (! rh->have_id_segment) ) // FIXME: have_id_segment is always 'true' here! - continue; /* infix existence mismatch */ - if ( ( (NULL == suffix_url) - ^ (NULL == rh->url_suffix) ) ) - continue; /* suffix existence mismatch */ - if ( (NULL != suffix_url) && - ( (suffix_strlen != strlen (rh->url_suffix)) || - (0 != memcmp (suffix_url, - rh->url_suffix, - suffix_strlen)) ) ) - continue; /* suffix content mismatch */ - } url_found = true; if (0 == strcasecmp (method, MHD_HTTP_METHOD_OPTIONS)) @@ -1707,10 +1762,65 @@ url_handler (void *cls, } if ( (NULL == hc->rh) && (url_found) ) - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_METHOD_NOT_ALLOWED, - TALER_EC_GENERIC_METHOD_INVALID, - method); + { + struct MHD_Response *reply; + MHD_RESULT ret; + char *allowed = NULL; + + GNUNET_break_op (0); + for (unsigned int i = 0; NULL != handlers[i].url_prefix; i++) + { + struct TMH_RequestHandler *rh = &handlers[i]; + + if (! prefix_match (rh, + url, + prefix_strlen, + infix_url, + infix_strlen, + suffix_url, + suffix_strlen)) + continue; + if (NULL == allowed) + { + allowed = GNUNET_strdup (rh->method); + } + else + { + char *tmp; + + GNUNET_asprintf (&tmp, + "%s, %s", + allowed, + rh->method); + GNUNET_free (allowed); + allowed = tmp; + } + if (0 == strcasecmp (rh->method, + MHD_HTTP_METHOD_GET)) + { + char *tmp; + + GNUNET_asprintf (&tmp, + "%s, %s", + allowed, + MHD_HTTP_METHOD_HEAD); + GNUNET_free (allowed); + allowed = tmp; + } + } + reply = TALER_MHD_make_error (TALER_EC_GENERIC_METHOD_INVALID, + method); + GNUNET_break (MHD_YES == + MHD_add_response_header (reply, + MHD_HTTP_HEADER_ALLOW, + allowed)); + GNUNET_free (allowed); + ret = MHD_queue_response (connection, + MHD_HTTP_METHOD_NOT_ALLOWED, + reply); + MHD_destroy_response (reply); + return ret; + } if (NULL == hc->rh) return TALER_MHD_reply_with_error (connection, MHD_HTTP_NOT_FOUND, |