physfshttpd: serve up directory listings, a few other cleanups.
This commit is contained in:
parent
2270b3c3c2
commit
98278f787b
|
@ -34,6 +34,7 @@
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
@ -64,45 +65,68 @@ typedef struct
|
||||||
} http_args;
|
} http_args;
|
||||||
|
|
||||||
|
|
||||||
static char *txt404 =
|
#define txt404 \
|
||||||
"HTTP/1.0 404 Not Found\n"
|
"HTTP/1.0 404 Not Found\n" \
|
||||||
"Connection: close\n"
|
"Connection: close\n" \
|
||||||
"Content-Type: text/html; charset=utf-8\n"
|
"Content-Type: text/html; charset=utf-8\n" \
|
||||||
"\n"
|
"\n" \
|
||||||
"<html><head><title>404 Not Found</title></head>\n"
|
"<html><head><title>404 Not Found</title></head>\n" \
|
||||||
"<body>Can't find that.</body></html>\n\n";
|
"<body>Can't find '%s'.</body></html>\n\n" \
|
||||||
|
|
||||||
static char *txt200 =
|
#define txt200 \
|
||||||
"HTTP/1.0 200 OK\n"
|
"HTTP/1.0 200 OK\n" \
|
||||||
"Connection: close\n"
|
"Connection: close\n" \
|
||||||
"Content-Type: text/plain; charset=utf-8\n"
|
"Content-Type: %s\n" \
|
||||||
"\n";
|
"\n"
|
||||||
|
|
||||||
static const char *lastError(void)
|
static const char *lastError(void)
|
||||||
{
|
{
|
||||||
return PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode());
|
return PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode());
|
||||||
} /* lastError */
|
} /* 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 */
|
} /* 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)
|
static void feed_file_http(const char *ipstr, int sock, const char *fname)
|
||||||
{
|
{
|
||||||
PHYSFS_File *in = PHYSFS_openRead(fname);
|
PHYSFS_File *in = PHYSFS_openRead(fname);
|
||||||
|
|
||||||
printf("%s: requested [%s].\n", ipstr, fname);
|
|
||||||
if (in == NULL)
|
if (in == NULL)
|
||||||
{
|
{
|
||||||
printf("%s: Can't open [%s]: %s.\n",
|
printf("%s: Can't open [%s]: %s.\n", ipstr, fname, lastError());
|
||||||
ipstr, fname, lastError());
|
writeString(ipstr, sock, txt404, fname);
|
||||||
if (!writeAll(sock, txt404, strlen(txt404)))
|
|
||||||
printf("%s: Write error to socket.\n", ipstr);
|
|
||||||
return;
|
return;
|
||||||
} /* if */
|
} /* if */
|
||||||
|
|
||||||
if (writeAll(sock, txt200, strlen(txt200)))
|
/* !!! FIXME: mimetype */
|
||||||
|
if (writeString(ipstr, sock, txt200, "text/plain; charset=utf-8"))
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
@ -114,9 +138,8 @@ static void feed_file_http(const char *ipstr, int sock, const char *fname)
|
||||||
break;
|
break;
|
||||||
} /* if */
|
} /* 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;
|
break;
|
||||||
} /* else if */
|
} /* else if */
|
||||||
} while (!PHYSFS_eof(in));
|
} while (!PHYSFS_eof(in));
|
||||||
|
@ -126,6 +149,69 @@ static void feed_file_http(const char *ipstr, int sock, const char *fname)
|
||||||
} /* feed_file_http */
|
} /* 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)
|
static void *do_http(void *_args)
|
||||||
{
|
{
|
||||||
http_args *args = (http_args *) _args;
|
http_args *args = (http_args *) _args;
|
||||||
|
@ -158,7 +244,7 @@ static void *do_http(void *_args)
|
||||||
ptr = strchr(buffer + 5, ' ');
|
ptr = strchr(buffer + 5, ' ');
|
||||||
if (ptr != NULL)
|
if (ptr != NULL)
|
||||||
*ptr = '\0';
|
*ptr = '\0';
|
||||||
feed_file_http(ipstr, args->sock, buffer + 4);
|
feed_http_request(ipstr, args->sock, buffer + 4);
|
||||||
} /* if */
|
} /* if */
|
||||||
} /* else */
|
} /* else */
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue