physfshttpd: serve up directory listings, a few other cleanups.

This commit is contained in:
Ryan C. Gordon 2017-08-14 22:47:02 -04:00
parent 2270b3c3c2
commit 98278f787b
1 changed files with 109 additions and 23 deletions

View File

@ -34,6 +34,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
@ -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"
"<html><head><title>404 Not Found</title></head>\n"
"<body>Can't find that.</body></html>\n\n";
#define txt404 \
"HTTP/1.0 404 Not Found\n" \
"Connection: close\n" \
"Content-Type: text/html; charset=utf-8\n" \
"\n" \
"<html><head><title>404 Not Found</title></head>\n" \
"<body>Can't find '%s'.</body></html>\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,
"<html><head><title>Directory %s</title></head>"
"<body><p><h1>Directory %s</h1></p><p><ul>\n",
dname, dname))
return;
if (strcmp(dname, "/") == 0)
dname = "";
for (i = 0; list[i]; i++)
{
const char *fname = list[i];
if (!writeString(ipstr, sock,
"<li><a href='%s/%s'>%s</a></li>\n", dname, fname, fname))
break;
} /* for */
writeString(ipstr, sock, "</ul></body></html>\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 */