From d9bb874591c63f2efbfc1c4c953934251c700e9f Mon Sep 17 00:00:00 2001 From: Xavier Del Campo Romero Date: Mon, 20 Mar 2023 03:32:00 +0100 Subject: Send response on quota exceeded So far, slcl would just close the connection with a client when the Content-Length of an incoming request exceeded the user quota, without any meaningful information given back to the user. Now, slcl responds with a HTML file with meaningful information about the error. Limitations: - While this commits has been successfully tested on ungoogled-chromium, LibreWolf (and I assume Firefox and any other derivates too) does not seem to receive the response from the server. - However, this issue only occurred during local testing, but not on remote instances. --- page.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) (limited to 'page.c') diff --git a/page.c b/page.c index 17adb8a..5cbb0a7 100644 --- a/page.c +++ b/page.c @@ -1311,3 +1311,93 @@ end: return ret; } + +int page_quota_exceeded(struct http_response *const r, + const unsigned long long len, const unsigned long long quota) +{ + int ret = -1; + struct dynstr msg, out; + char q[sizeof MAXSIZEFMT], l[sizeof q]; + struct html_node *const html = html_node_alloc("html"), + *head, *body; + + dynstr_init(&msg); + dynstr_init(&out); + + if (!html) + { + fprintf(stderr, "%s: html_node_alloc failed\n", __func__); + goto end; + } + else if (!(head = html_node_add_child(html, "head"))) + { + fprintf(stderr, "%s: html_node_add_child head failed\n", __func__); + goto end; + } + else if (!(body = html_node_add_child(html, "body"))) + { + fprintf(stderr, "%s: html_node_add_child body failed\n", __func__); + goto end; + } + else if (common_head(head, NULL)) + { + fprintf(stderr, "%s: common_head failed\n", __func__); + goto end; + } + else if (size_units(quota, q, sizeof q)) + { + fprintf(stderr, "%s: size_units quota failed\n", __func__); + goto end; + } + else if (size_units(len, l, sizeof l)) + { + fprintf(stderr, "%s: size_units len failed\n", __func__); + goto end; + } + else if (dynstr_append(&msg, "Maximum quota exceeded: %s " + "(requested size: %s)", q, l)) + { + fprintf(stderr, "%s: dynstr_append msg failed\n", __func__); + goto end; + } + else if (html_node_set_value(body, msg.str)) + { + fprintf(stderr, "%s: html_node_set_value msg failed\n", __func__); + goto end; + } + else if (dynstr_append(&out, DOCTYPE_TAG)) + { + fprintf(stderr, "%s: dynstr_prepend failed\n", __func__); + goto end; + } + else if (html_serialize(html, &out)) + { + fprintf(stderr, "%s: html_serialize failed\n", __func__); + goto end; + } + + *r = (const struct http_response) + { + .status = HTTP_STATUS_PAYLOAD_TOO_LARGE, + .buf.rw = out.str, + .n = out.len, + .free = free + }; + + if (http_response_add_header(r, "Content-Type", "text/html")) + { + fprintf(stderr, "%s: http_response_add_header failed\n", __func__); + goto end; + } + + ret = 0; + +end: + html_node_free(html); + dynstr_free(&msg); + + if (ret) + dynstr_free(&out); + + return ret; +} -- cgit v1.2.3