OpenBSD's httpd refuses to serve an index file and returns a nasty
"500 Internal Server Error" when the URL that's being requested does
not contain a file name and there's a rewrite rule for the path in
httpd.conf. Here's an excerpt from my httpd.conf that demonstrates
the issue:
location match "/~(.*)" {
request rewrite "/users/%1"
}
Example URL: https://example.org/~joe/
This doesn't work properly because the pointer http_path_alias is
assigned in server_response() whenever a rewrite rule is processed,
but is subsequently checked for NULL in server_file_access() in an
attempt to detect an infinite recursive loop.
I've attached a patch for your consideration. It makes a lot of
sense to me to simply use a counter. This even improves readability.
Let me know what you think, thanks!
Sincerely, Erik
Index: usr.sbin/httpd/server_file.c
===================================================================
RCS file: /cvs/src/usr.sbin/httpd/server_file.c,v
retrieving revision 1.75
diff -u -r1.75 server_file.c
--- usr.sbin/httpd/server_file.c 15 Aug 2022 09:40:14 -0000 1.75
+++ usr.sbin/httpd/server_file.c 2 Jun 2023 04:36:02 -0000
@@ -38,7 +38,7 @@
#define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b))
int server_file_access(struct httpd *, struct client *,
- char *, size_t);
+ char *, size_t, int);
int server_file_request(struct httpd *, struct client *,
char *, struct timespec *);
int server_partial_file_request(struct httpd *, struct client *,
@@ -52,7 +52,7 @@
int
server_file_access(struct httpd *env, struct client *clt,
- char *path, size_t len)
+ char *path, size_t len, int attempts)
{
struct http_descriptor *desc = clt->clt_descreq;
struct server_config *srv_conf = clt->clt_srv_conf;
@@ -72,7 +72,7 @@
goto fail;
}
- if (desc->http_path_alias != NULL) {
+ if (attempts > 0) {
/* Recursion - the index "file" is a directory? */
errno = EINVAL;
goto fail;
@@ -111,7 +111,7 @@
goto fail;
}
- ret = server_file_access(env, clt, path, len);
+ ret = server_file_access(env, clt, path, len, attempts + 1);
if (ret == 404) {
/*
* Index file not found; fail if auto-indexing is
@@ -179,7 +179,7 @@
}
/* Returns HTTP status code on error */
- if ((ret = server_file_access(env, clt, path, sizeof(path))) > 0) {
+ if ((ret = server_file_access(env, clt, path, sizeof(path), 0)) > 0) {
errstr = desc->http_path_alias != NULL ?
desc->http_path_alias : desc->http_path;
goto abort;