aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2021-04-01 12:07:48 +0200
committerChristian Grothoff <christian@grothoff.org>2021-04-01 12:09:58 +0200
commitfb6d4b23a34436310b9646f14913ba1c4cd4b071 (patch)
treed1e1241069e48c9aa6cdf0c14d8899adf89e2f2e /src/backend
parent9b729aceb6e02c3a8ef7a8f0b010cd32263da33c (diff)
downloadmerchant-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.c184
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,