From 5341e4d62ab3ff635af98c5fc2326ae9f717322f Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 21 Jun 2020 12:05:56 +0200 Subject: address 413 fixme --- src/backend/taler-merchant-httpd.c | 51 ++++++++++++++++++++++ src/backend/taler-merchant-httpd.h | 11 +++++ .../taler-merchant-httpd_private-post-reserves.c | 1 + 3 files changed, 63 insertions(+) diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c index f3d8d757..314e65a4 100644 --- a/src/backend/taler-merchant-httpd.c +++ b/src/backend/taler-merchant-httpd.c @@ -66,6 +66,11 @@ */ #define UNIX_BACKLOG 500 +/** + * Default maximum upload size permitted. Can be overridden + * per handler. + */ +#define DEFAULT_MAX_UPLOAD_SIZE (16 * 1024) /** * Which currency do we use? @@ -1029,6 +1034,22 @@ url_handler (void *cls, { int res; + if ( (hc->total_upload + *upload_data_size < hc->total_upload) || + (hc->total_upload + *upload_data_size > hc->rh->max_upload) ) + { + /* Client exceeds upload limit. Should _usually_ be checked earlier + when we look at the MHD_HTTP_HEADER_CONTENT_LENGTH, alas with + chunked encoding an uploader MAY have ommitted this, and thus + not permitted us to check on time. In this case, we just close + the connection once it exceeds our limit (instead of waiting + for the upload to complete and then fail). This could theoretically + cause some clients to retry, alas broken or malicious clients + are likely to retry anyway, so little we can do about it, and + failing earlier seems the best option here. */// + GNUNET_break_op (0); + return MHD_NO; + } + hc->total_upload += *upload_data_size; res = TALER_MHD_parse_post_json (connection, &hc->json_parse_context, upload_data, @@ -1265,6 +1286,36 @@ url_handler (void *cls, MHD_HTTP_METHOD_PATCH)) ); if (hc->has_body) { + const char *cl; + + cl = MHD_lookup_connection_value (connection, + MHD_HEADER_KIND, + MHD_HTTP_HEADER_CONTENT_LENGTH); + if (NULL != cl) + { + unsigned long long cv; + size_t mul = hc->rh->max_upload; + + if (0 == mul) + mul = DEFAULT_MAX_UPLOAD_SIZE; + if (1 != sscanf (cl, + "%llu", + &cv)) + { + /* Not valid HTTP request, just close connection. */ + GNUNET_break_op (0); + return MHD_NO; + } + if (cv > mul) + { + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_PAYLOAD_TOO_LARGE, + TALER_EC_UPLOAD_EXCEEDS_LIMIT, + "upload exceeds limit"); + } + } + /* FIXME: Maybe check for maximum upload size here and refuse if it is too big? (Note: maximum upload size may need to vary based on the handler.) */ diff --git a/src/backend/taler-merchant-httpd.h b/src/backend/taler-merchant-httpd.h index 7e1090d3..42d86d3f 100644 --- a/src/backend/taler-merchant-httpd.h +++ b/src/backend/taler-merchant-httpd.h @@ -197,6 +197,12 @@ struct TMH_RequestHandler */ size_t data_size; + /** + * Maximum upload size allowed for this handler. + * 0 for DEFAULT_MAX_UPLOAD_SIZE + */ + size_t max_upload; + /** * Handler to be called for this URL/METHOD combination. * @@ -285,6 +291,11 @@ struct TMH_HandlerContext */ void *json_parse_context; + /** + * Total size of the upload so far. + */ + uint64_t total_upload; + /** * Set to true if this is an #MHD_HTTP_METHOD_POST or #MHD_HTTP_METHOD_PATCH request. * (In principle #MHD_HTTP_METHOD_PUT may also belong, but we do not have PUTs diff --git a/src/backend/taler-merchant-httpd_private-post-reserves.c b/src/backend/taler-merchant-httpd_private-post-reserves.c index 01bba5d4..5a691f4d 100644 --- a/src/backend/taler-merchant-httpd_private-post-reserves.c +++ b/src/backend/taler-merchant-httpd_private-post-reserves.c @@ -25,6 +25,7 @@ #include "platform.h" #include "taler-merchant-httpd_exchanges.h" #include "taler-merchant-httpd_private-post-reserves.h" +#include "taler-merchant-httpd_reserves.h" #include -- cgit v1.2.3