From 98278f787beda996cf112ea26aae623357d12795 Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon"
Date: Mon, 14 Aug 2017 22:47:02 -0400
Subject: [PATCH] physfshttpd: serve up directory listings, a few other
cleanups.
---
extras/physfshttpd.c | 132 +++++++++++++++++++++++++++++++++++--------
1 file changed, 109 insertions(+), 23 deletions(-)
diff --git a/extras/physfshttpd.c b/extras/physfshttpd.c
index 6ae8fbed..9e0df6bb 100644
--- a/extras/physfshttpd.c
+++ b/extras/physfshttpd.c
@@ -34,6 +34,7 @@
#include
#include
+#include
#include
#include
#include
@@ -64,45 +65,68 @@ typedef struct
} http_args;
-static char *txt404 =
-"HTTP/1.0 404 Not Found\n"
-"Connection: close\n"
-"Content-Type: text/html; charset=utf-8\n"
-"\n"
-"404 Not Found\n"
-"Can't find that.\n\n";
+#define txt404 \
+ "HTTP/1.0 404 Not Found\n" \
+ "Connection: close\n" \
+ "Content-Type: text/html; charset=utf-8\n" \
+ "\n" \
+ "404 Not Found\n" \
+ "Can't find '%s'.\n\n" \
-static char *txt200 =
-"HTTP/1.0 200 OK\n"
-"Connection: close\n"
-"Content-Type: text/plain; charset=utf-8\n"
-"\n";
+#define txt200 \
+ "HTTP/1.0 200 OK\n" \
+ "Connection: close\n" \
+ "Content-Type: %s\n" \
+ "\n"
static const char *lastError(void)
{
return PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode());
} /* lastError */
-static int writeAll(const int fd, const void *buf, const size_t len)
+static int writeAll(const char *ipstr, const int sock, void *buf, const size_t len)
{
- return (write(fd, buf, len) == len);
+ if (write(sock, buf, len) != len)
+ {
+ printf("%s: Write error to socket.\n", ipstr);
+ return 0;
+ } /* if */
+
+ return 1;
} /* writeAll */
+static int writeString(const char *ipstr, const int sock, const char *fmt, ...)
+{
+ /* none of this is robust against large strings or HTML escaping. */
+ char buffer[1024];
+ int len;
+ va_list ap;
+ va_start(ap, fmt);
+ len = vsnprintf(buffer, sizeof (buffer), fmt, ap);
+ va_end(ap);
+ if (len < 0)
+ {
+ printf("uhoh, vsnprintf() failed!\n");
+ return 0;
+ } /* if */
+
+ return writeAll(ipstr, sock, buffer, len);
+} /* writeString */
+
+
static void feed_file_http(const char *ipstr, int sock, const char *fname)
{
PHYSFS_File *in = PHYSFS_openRead(fname);
- printf("%s: requested [%s].\n", ipstr, fname);
if (in == NULL)
{
- printf("%s: Can't open [%s]: %s.\n",
- ipstr, fname, lastError());
- if (!writeAll(sock, txt404, strlen(txt404)))
- printf("%s: Write error to socket.\n", ipstr);
+ printf("%s: Can't open [%s]: %s.\n", ipstr, fname, lastError());
+ writeString(ipstr, sock, txt404, fname);
return;
} /* if */
- if (writeAll(sock, txt200, strlen(txt200)))
+ /* !!! FIXME: mimetype */
+ if (writeString(ipstr, sock, txt200, "text/plain; charset=utf-8"))
{
do
{
@@ -114,9 +138,8 @@ static void feed_file_http(const char *ipstr, int sock, const char *fname)
break;
} /* if */
- else if (!writeAll(sock, buffer, (size_t) br))
+ else if (!writeAll(ipstr, sock, buffer, (size_t) br))
{
- printf("%s: Write error to socket.\n", ipstr);
break;
} /* else if */
} while (!PHYSFS_eof(in));
@@ -126,6 +149,69 @@ static void feed_file_http(const char *ipstr, int sock, const char *fname)
} /* feed_file_http */
+static void feed_dirlist_http(const char *ipstr, int sock,
+ const char *dname, char **list)
+{
+ int i;
+
+ if (!writeString(ipstr, sock, txt200, "text/html; charset=utf-8"))
+ return;
+
+ else if (!writeString(ipstr, sock,
+ "Directory %s"
+ "Directory %s
\n",
+ dname, dname))
+ return;
+
+ if (strcmp(dname, "/") == 0)
+ dname = "";
+
+ for (i = 0; list[i]; i++)
+ {
+ const char *fname = list[i];
+ if (!writeString(ipstr, sock,
+ "- %s
\n", dname, fname, fname))
+ break;
+ } /* for */
+
+ writeString(ipstr, sock, "
\n");
+} /* feed_dirlist_http */
+
+static void feed_dir_http(const char *ipstr, int sock, const char *dname)
+{
+ char **list = PHYSFS_enumerateFiles(dname);
+ if (list == NULL)
+ {
+ printf("%s: Can't enumerate directory [%s]: %s.\n",
+ ipstr, dname, lastError());
+ writeString(ipstr, sock, txt404, dname);
+ return;
+ } /* if */
+
+ feed_dirlist_http(ipstr, sock, dname, list);
+ PHYSFS_freeList(list);
+} /* feed_dir_http */
+
+static void feed_http_request(const char *ipstr, int sock, const char *fname)
+{
+ PHYSFS_Stat statbuf;
+
+ printf("%s: requested [%s].\n", ipstr, fname);
+
+ if (!PHYSFS_stat(fname, &statbuf))
+ {
+ printf("%s: Can't stat [%s]: %s.\n", ipstr, fname, lastError());
+ writeString(ipstr, sock, txt404, fname);
+ return;
+ } /* if */
+
+ if (statbuf.filetype == PHYSFS_FILETYPE_DIRECTORY)
+ feed_dir_http(ipstr, sock, fname);
+ else
+ feed_file_http(ipstr, sock, fname);
+} /* feed_http_request */
+
+
static void *do_http(void *_args)
{
http_args *args = (http_args *) _args;
@@ -158,7 +244,7 @@ static void *do_http(void *_args)
ptr = strchr(buffer + 5, ' ');
if (ptr != NULL)
*ptr = '\0';
- feed_file_http(ipstr, args->sock, buffer + 4);
+ feed_http_request(ipstr, args->sock, buffer + 4);
} /* if */
} /* else */