diff --git a/NEWS b/NEWS
index 9dc2d1d..24f34ef 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-Pound -- history of user-visible changes. 2024-03-29
+Pound -- history of user-visible changes. 2024-03-30
See the end of file for copying conditions.
Pound is a continuation of the software originally developed by
@@ -46,6 +46,11 @@ Err400 - Err503 statements used in previous versions. These
statements are still supported for backward compatibility, although
their use is discouraged.
+* New statement: MaxURI
+
+This statement sets the maximum allowed length of the request URI.
+It can be used in ListenHTTP and ListenHTTPS sections.
+
* Bugfixes
** Don't try to access the include directory, unless needed by configuration.
diff --git a/doc/pound.8 b/doc/pound.8
index f3e355a..89466a3 100644
--- a/doc/pound.8
+++ b/doc/pound.8
@@ -14,7 +14,7 @@
.\"
.\" You should have received a copy of the GNU General Public License
.\" along with pound. If not, see .
-.TH POUND 8 "March 28, 2024" "pound" "System Manager's Manual"
+.TH POUND 8 "March 30, 2024" "pound" "System Manager's Manual"
.SH NAME
pound \- HTTP/HTTPS reverse-proxy and load-balancer
.SH SYNOPSIS
@@ -889,6 +889,10 @@ Maximum allowed size of incoming request. All requests will be limited
to these many bytes. If a request contains more data than allowed, an
error 413 is returned. Default: unlimited.
.TP
+\fBMaxURI\fR \fIn\fR
+Maximum allowed length of an URI. If the URI of a request is longer than
+\fIn\fR bytes, an error 414 is returned. Default: unlimited.
+.TP
\fBRewriteLocation\fR 0|1|2
If set to 1, force
.B pound
diff --git a/doc/pound.texi b/doc/pound.texi
index 2b2d8a8..ad65c88 100644
--- a/doc/pound.texi
+++ b/doc/pound.texi
@@ -2503,6 +2503,14 @@ A request bigger than that will be responded with status
By default, there is no limit on the request size.
@end deffn
+@deffn {ListenHTTP directive} MaxURI @var{n}
+Limits the maximum allowed length of incoming request URI.
+A request with an URI longer than that will be responded with status
+414.
+
+By default, there is no limit on the URI length.
+@end deffn
+
@deffn {ListenHTTP directive} CheckURL "@var{pattern}"
Define a pattern that must be matched by each request sent to this
listener. A request that does not match will be returned a 501
diff --git a/src/config.c b/src/config.c
index d89cf25..92384f2 100644
--- a/src/config.c
+++ b/src/config.c
@@ -4028,8 +4028,8 @@ static PARSER_TABLE http_parsetab[] = {
{ "Client", assign_timeout, NULL, offsetof (LISTENER, to) },
{ "CheckURL", listener_parse_checkurl },
{ "ErrorFile", parse_errorfile, NULL, offsetof (LISTENER, http_err) },
- { "MaxRequest", assign_CONTENT_LENGTH, NULL, offsetof (LISTENER, max_req) },
-
+ { "MaxRequest", assign_CONTENT_LENGTH, NULL, offsetof (LISTENER, max_req_size) },
+ { "MaxURI", assign_unsigned, NULL, offsetof (LISTENER, max_uri_length) },
{ "Rewrite", parse_rewrite, NULL, offsetof (LISTENER, rewrite) },
{ "SetHeader", SETFN_SVC_NAME (set_header), NULL, offsetof (LISTENER, rewrite) },
{ "DeleteHeader", SETFN_SVC_NAME (delete_header), NULL, offsetof (LISTENER, rewrite) },
@@ -4681,7 +4681,8 @@ static PARSER_TABLE https_parsetab[] = {
{ "Client", assign_timeout, NULL, offsetof (LISTENER, to) },
{ "CheckURL", listener_parse_checkurl },
{ "ErrorFile", parse_errorfile, NULL, offsetof (LISTENER, http_err) },
- { "MaxRequest", assign_CONTENT_LENGTH, NULL, offsetof (LISTENER, max_req) },
+ { "MaxRequest", assign_CONTENT_LENGTH, NULL, offsetof (LISTENER, max_req_size) },
+ { "MaxURI", assign_unsigned, NULL, offsetof (LISTENER, max_uri_length) },
{ "Rewrite", parse_rewrite, NULL, offsetof (LISTENER, rewrite) },
{ "SetHeader", SETFN_SVC_NAME (set_header), NULL, offsetof (LISTENER, rewrite) },
diff --git a/src/http.c b/src/http.c
index 84a0976..5aa9f9e 100644
--- a/src/http.c
+++ b/src/http.c
@@ -4095,7 +4095,7 @@ send_to_backend (POUND_HTTP *phttp, int chunked, CONTENT_LENGTH content_length)
*/
int rc = copy_chunks (phttp->cl, phttp->be, NULL,
phttp->backend->be_type != BE_BACKEND,
- phttp->lstn->max_req);
+ phttp->lstn->max_req_size);
if (rc != HTTP_STATUS_OK)
{
log_error (phttp, rc, errno, "error sending chunks");
@@ -4603,11 +4603,36 @@ do_http (POUND_HTTP *phttp)
}
}
+ if (phttp->lstn->max_uri_length > 0)
+ {
+ int rc;
+ char const *url;
+ rc = http_request_get_url (&phttp->request, &url);
+ if (rc == RETRIEVE_OK)
+ {
+ size_t urlen;
+ if ((urlen = strlen (url)) > phttp->lstn->max_uri_length)
+ {
+ log_error (phttp, HTTP_STATUS_URI_TOO_LONG, 0,
+ "URI too long: %zu bytes",
+ urlen);
+ http_err_reply (phttp, HTTP_STATUS_URI_TOO_LONG);
+ return;
+ }
+ }
+ else
+ {
+ log_error (phttp, HTTP_STATUS_INTERNAL_SERVER_ERROR, 0,
+ "can't get URL from the request (shouldn't happen)");
+ goto err;
+ }
+ }
+
/*
* possibly limited request size
*/
- if (phttp->lstn->max_req > 0 && content_length > 0
- && content_length > phttp->lstn->max_req)
+ if (phttp->lstn->max_req_size > 0 && content_length > 0
+ && content_length > phttp->lstn->max_req_size)
{
log_error (phttp, HTTP_STATUS_PAYLOAD_TOO_LARGE, 0,
"request too large: %"PRICLEN" bytes",
diff --git a/src/pound.h b/src/pound.h
index 32e0e1f..c9aa71b 100644
--- a/src/pound.h
+++ b/src/pound.h
@@ -734,7 +734,8 @@ typedef struct _listener
unsigned to; /* client time-out */
regex_t *url_pat; /* pattern to match the request URL against */
char *http_err[HTTP_STATUS_MAX]; /* error messages */
- CONTENT_LENGTH max_req; /* max. request size */
+ CONTENT_LENGTH max_req_size; /* max. request size */
+ unsigned max_uri_length; /* max. URI length */
int rewr_loc; /* rewrite location response */
int rewr_dest; /* rewrite destination header */
int disabled; /* true if the listener is disabled */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 0129a34..9bdb7e4 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -95,6 +95,7 @@ TESTSUITE_AT = \
logsup.at\
lstset.at\
maxrequest.at\
+ maxuri.at\
multival.at\
nb.at\
not.at\
diff --git a/tests/maxuri.at b/tests/maxuri.at
new file mode 100644
index 0000000..3ef075d
--- /dev/null
+++ b/tests/maxuri.at
@@ -0,0 +1,37 @@
+# This file is part of pound testsuite. -*- autotest -*-
+# Copyright (C) 2022-2024 Sergey Poznyakoff
+#
+# Pound is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# Pound is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with pound. If not, see .
+AT_SETUP([MaxURI])
+AT_KEYWORDS([maxuri])
+
+PT_CHECK([ListenHTTP
+ MaxURI 8
+ Service
+ Backend
+ Address
+ Port
+ End
+ End
+End
+],
+[GET /echo/file
+
+end
+
+414
+end
+])
+
+AT_CLEANUP
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 3f98880..28f05f6 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -58,6 +58,7 @@ m4_include([xhttp.at])
m4_include([checkurl.at])
m4_include([errfile.at])
m4_include([maxrequest.at])
+m4_include([maxuri.at])
m4_include([rewriteloc.at])
m4_include([nb.at])
m4_include([chunked.at])