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;

Reply via email to