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 */