mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-23 13:52:28 +00:00
Enable serving zip directory entries
This commit is contained in:
parent
1753b669cf
commit
7dc8973567
3 changed files with 131 additions and 50 deletions
|
@ -1,2 +1,3 @@
|
||||||
-- special script called by main redbean process at startup
|
-- special script called by main redbean process at startup
|
||||||
ProgramRedirect(0, '/favicon.ico', '/tool/net/redbean.ico')
|
ProgramRedirect(0, '/favicon.ico', '/tool/net/redbean.ico')
|
||||||
|
HidePath('/usr/share/zoneinfo/')
|
||||||
|
|
|
@ -36,6 +36,7 @@ TOOL_NET_DIRECTDEPS = \
|
||||||
LIBC_SYSV \
|
LIBC_SYSV \
|
||||||
LIBC_SYSV_CALLS \
|
LIBC_SYSV_CALLS \
|
||||||
LIBC_TIME \
|
LIBC_TIME \
|
||||||
|
LIBC_TINYMATH \
|
||||||
LIBC_UNICODE \
|
LIBC_UNICODE \
|
||||||
LIBC_X \
|
LIBC_X \
|
||||||
NET_HTTP \
|
NET_HTTP \
|
||||||
|
|
|
@ -345,7 +345,6 @@ static size_t hdrsize;
|
||||||
static size_t msgsize;
|
static size_t msgsize;
|
||||||
static size_t amtread;
|
static size_t amtread;
|
||||||
static char *luaheaderp;
|
static char *luaheaderp;
|
||||||
struct Strings stagedirs;
|
|
||||||
static const char *sauce;
|
static const char *sauce;
|
||||||
static const char *brand;
|
static const char *brand;
|
||||||
static const char *pidpath;
|
static const char *pidpath;
|
||||||
|
@ -355,6 +354,8 @@ static size_t contentlength;
|
||||||
static int64_t cacheseconds;
|
static int64_t cacheseconds;
|
||||||
static uint8_t gzip_footer[8];
|
static uint8_t gzip_footer[8];
|
||||||
static const char *serverheader;
|
static const char *serverheader;
|
||||||
|
static struct Strings stagedirs;
|
||||||
|
static struct Strings hidepaths;
|
||||||
|
|
||||||
static struct Buffer logo;
|
static struct Buffer logo;
|
||||||
static struct Buffer inbuf;
|
static struct Buffer inbuf;
|
||||||
|
@ -508,7 +509,7 @@ static const char *FindContentType(uint64_t ext) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *GetContentType(const char *path, size_t n) {
|
static const char *GetContentType2(const char *path, size_t n) {
|
||||||
size_t i;
|
size_t i;
|
||||||
uint64_t x;
|
uint64_t x;
|
||||||
const char *p, *r;
|
const char *p, *r;
|
||||||
|
@ -521,7 +522,15 @@ static const char *GetContentType(const char *path, size_t n) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "application/octet-stream";
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *GetContentType(struct Asset *a, const char *path, size_t n) {
|
||||||
|
return firstnonnull(
|
||||||
|
GetContentType2(path, n),
|
||||||
|
firstnonnull(GetContentType2(ZIP_LFILE_NAME(zmap + a->lf),
|
||||||
|
ZIP_LFILE_NAMESIZE(zmap + a->lf)),
|
||||||
|
"application/octet-stream"));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DescribeAddress(char buf[32], const struct sockaddr_in *addr) {
|
static void DescribeAddress(char buf[32], const struct sockaddr_in *addr) {
|
||||||
|
@ -575,6 +584,11 @@ static char *RemoveTrailingSlashes(char *s) {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void AddString(struct Strings *l, char *s) {
|
||||||
|
l->p = xrealloc(l->p, ++l->n * sizeof(*l->p));
|
||||||
|
l->p[l->n - 1] = s;
|
||||||
|
}
|
||||||
|
|
||||||
static void AddStagingDirectory(const char *dirpath) {
|
static void AddStagingDirectory(const char *dirpath) {
|
||||||
char *s;
|
char *s;
|
||||||
s = RemoveTrailingSlashes(strdup(dirpath));
|
s = RemoveTrailingSlashes(strdup(dirpath));
|
||||||
|
@ -582,8 +596,7 @@ static void AddStagingDirectory(const char *dirpath) {
|
||||||
fprintf(stderr, "error: not a directory: %s\n", s);
|
fprintf(stderr, "error: not a directory: %s\n", s);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
stagedirs.p = xrealloc(stagedirs.p, ++stagedirs.n * sizeof(*stagedirs.p));
|
AddString(&stagedirs, s);
|
||||||
stagedirs.p[stagedirs.n - 1] = s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void GetOpts(int argc, char *argv[]) {
|
static void GetOpts(int argc, char *argv[]) {
|
||||||
|
@ -884,6 +897,11 @@ static void IndexAssets(void) {
|
||||||
ZIP_CFILE_NAMESIZE(zmap + cf), ZIP_CFILE_NAME(zmap + cf));
|
ZIP_CFILE_NAMESIZE(zmap + cf), ZIP_CFILE_NAME(zmap + cf));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (ZIP_CFILE_NAMESIZE(zmap + cf) > 1 &&
|
||||||
|
ZIP_CFILE_NAME(zmap + cf)[ZIP_CFILE_NAMESIZE(zmap + cf) - 1] == '/' &&
|
||||||
|
!ZIP_CFILE_UNCOMPRESSEDSIZE(zmap + cf)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
hash = Hash(ZIP_CFILE_NAME(zmap + cf), ZIP_CFILE_NAMESIZE(zmap + cf));
|
hash = Hash(ZIP_CFILE_NAME(zmap + cf), ZIP_CFILE_NAMESIZE(zmap + cf));
|
||||||
step = 0;
|
step = 0;
|
||||||
do {
|
do {
|
||||||
|
@ -932,19 +950,22 @@ static struct Asset *FindAsset(const char *path, size_t pathlen) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct Asset *LocateAssetZip(const char *path, size_t pathlen) {
|
static struct Asset *LocateAssetZip(const char *path, size_t pathlen) {
|
||||||
char *path2;
|
char *p2, *p3, *p4;
|
||||||
struct Asset *a;
|
struct Asset *a;
|
||||||
if (pathlen && path[0] == '/') ++path, --pathlen;
|
if (pathlen && path[0] == '/') ++path, --pathlen;
|
||||||
if (!(a = FindAsset(path, pathlen)) &&
|
if (!(a = FindAsset(path, pathlen)) &&
|
||||||
(!pathlen || (pathlen && path[pathlen - 1] == '/'))) {
|
(!pathlen || (pathlen && path[pathlen - 1] == '/'))) {
|
||||||
path2 = xmalloc(pathlen + 10);
|
p2 = strndup(path, pathlen);
|
||||||
memcpy(path2, path, pathlen);
|
p3 = xjoinpaths(p2, "index.lua");
|
||||||
memcpy(path2 + pathlen, "index.lua", 9);
|
LOGF("find asset %s", p3);
|
||||||
if (!(a = FindAsset(path2, pathlen + 9))) {
|
if (!(a = FindAsset(p3, strlen(p3)))) {
|
||||||
memcpy(path2 + pathlen, "index.html", 10);
|
p4 = xjoinpaths(p2, "index.html");
|
||||||
a = FindAsset(path2, pathlen + 10);
|
LOGF("find asset %s", p4);
|
||||||
|
a = FindAsset(p4, strlen(p4));
|
||||||
|
free(p4);
|
||||||
}
|
}
|
||||||
free(path2);
|
free(p3);
|
||||||
|
free(p2);
|
||||||
}
|
}
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
@ -1360,7 +1381,7 @@ static char *ServeAsset(struct Asset *a, const char *path, size_t pathlen) {
|
||||||
}
|
}
|
||||||
if (httpversion >= 100) {
|
if (httpversion >= 100) {
|
||||||
p = AppendHeader(p, "Last-Modified", a->lastmodifiedstr);
|
p = AppendHeader(p, "Last-Modified", a->lastmodifiedstr);
|
||||||
p = AppendContentType(p, GetContentType(path, pathlen));
|
p = AppendContentType(p, GetContentType(a, path, pathlen));
|
||||||
if (httpversion >= 101) {
|
if (httpversion >= 101) {
|
||||||
p = AppendCache(p, cacheseconds);
|
p = AppendCache(p, cacheseconds);
|
||||||
if (!IsCompressed(a)) {
|
if (!IsCompressed(a)) {
|
||||||
|
@ -1410,6 +1431,30 @@ static char *CommitOutput(char *p) {
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *GetAssetPath(uint32_t cf, size_t *out_size) {
|
||||||
|
char *p1, *p2;
|
||||||
|
size_t n1, n2;
|
||||||
|
p1 = ZIP_CFILE_NAME(zmap + cf);
|
||||||
|
n1 = ZIP_CFILE_NAMESIZE(zmap + cf);
|
||||||
|
p2 = malloc(1 + n1 + 1);
|
||||||
|
n2 = 1 + n1 + 1;
|
||||||
|
p2[0] = '/';
|
||||||
|
memcpy(p2 + 1, p1, n1);
|
||||||
|
p2[1 + n1] = '\0';
|
||||||
|
if (out_size) *out_size = 1 + n1;
|
||||||
|
return p2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IsHiddenPath(const char *s) {
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < hidepaths.n; ++i) {
|
||||||
|
if (startswith(s, hidepaths.p[i])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static int LuaServeAsset(lua_State *L) {
|
static int LuaServeAsset(lua_State *L) {
|
||||||
size_t pathlen;
|
size_t pathlen;
|
||||||
struct Asset *a;
|
struct Asset *a;
|
||||||
|
@ -1821,6 +1866,11 @@ static int LuaSetLogLevel(lua_State *L) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int LuaHidePath(lua_State *L) {
|
||||||
|
AddString(&hidepaths, strdup(luaL_checkstring(L, 1)));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int LuaLog(lua_State *L) {
|
static int LuaLog(lua_State *L) {
|
||||||
int level;
|
int level;
|
||||||
lua_Debug ar;
|
lua_Debug ar;
|
||||||
|
@ -1836,6 +1886,29 @@ static int LuaLog(lua_State *L) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int LuaIsHiddenPath(lua_State *L) {
|
||||||
|
lua_pushboolean(L, IsHiddenPath(luaL_checkstring(L, 1)));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int LuaGetZipPaths(lua_State *L) {
|
||||||
|
char *path;
|
||||||
|
uint32_t cf;
|
||||||
|
size_t i, n, pathlen;
|
||||||
|
lua_newtable(L);
|
||||||
|
i = 0;
|
||||||
|
n = ZIP_CDIR_RECORDS(zdir);
|
||||||
|
CHECK_EQ(kZipCdirHdrMagic, ZIP_CDIR_MAGIC(zdir));
|
||||||
|
for (cf = ZIP_CDIR_OFFSET(zdir); n--; cf += ZIP_CFILE_HDRSIZE(zmap + cf)) {
|
||||||
|
CHECK_EQ(kZipCfileHdrMagic, ZIP_CFILE_MAGIC(zmap + cf));
|
||||||
|
path = GetAssetPath(cf, &pathlen);
|
||||||
|
lua_pushlstring(L, path, pathlen);
|
||||||
|
lua_seti(L, -2, ++i);
|
||||||
|
free(path);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static void LuaRun(const char *path) {
|
static void LuaRun(const char *path) {
|
||||||
struct Asset *a;
|
struct Asset *a;
|
||||||
const char *code;
|
const char *code;
|
||||||
|
@ -1874,7 +1947,9 @@ static const luaL_Reg kLuaFuncs[] = {
|
||||||
{"GetServerAddr", LuaGetServerAddr}, //
|
{"GetServerAddr", LuaGetServerAddr}, //
|
||||||
{"GetUri", LuaGetUri}, //
|
{"GetUri", LuaGetUri}, //
|
||||||
{"GetVersion", LuaGetVersion}, //
|
{"GetVersion", LuaGetVersion}, //
|
||||||
|
{"GetZipPaths", LuaGetZipPaths}, //
|
||||||
{"HasParam", LuaHasParam}, //
|
{"HasParam", LuaHasParam}, //
|
||||||
|
{"HidePath", LuaHidePath}, //
|
||||||
{"LoadAsset", LuaLoadAsset}, //
|
{"LoadAsset", LuaLoadAsset}, //
|
||||||
{"Log", LuaLog}, //
|
{"Log", LuaLog}, //
|
||||||
{"ParseHttpDateTime", LuaParseHttpDateTime}, //
|
{"ParseHttpDateTime", LuaParseHttpDateTime}, //
|
||||||
|
@ -2108,10 +2183,10 @@ static char *ServeListing(void) {
|
||||||
char tb[64];
|
char tb[64];
|
||||||
int w, x, y;
|
int w, x, y;
|
||||||
struct tm tm;
|
struct tm tm;
|
||||||
|
char *p, *path;
|
||||||
int64_t lastmod;
|
int64_t lastmod;
|
||||||
uint32_t cf, lf;
|
uint32_t cf, lf;
|
||||||
size_t n, n1, n2;
|
size_t i, n, pathlen;
|
||||||
char *p, *p1, *p2;
|
|
||||||
struct EscapeResult r[3];
|
struct EscapeResult r[3];
|
||||||
AppendString("\
|
AppendString("\
|
||||||
<!doctype html>\n\
|
<!doctype html>\n\
|
||||||
|
@ -2128,8 +2203,11 @@ a {\n\
|
||||||
img {\n\
|
img {\n\
|
||||||
vertical-align: middle;\n\
|
vertical-align: middle;\n\
|
||||||
}\n\
|
}\n\
|
||||||
|
footer {\n\
|
||||||
|
font-size: 11pt;\n\
|
||||||
|
}\n\
|
||||||
</style>\n\
|
</style>\n\
|
||||||
<h1>\n");
|
<header><h1>\n");
|
||||||
if (logo.n) {
|
if (logo.n) {
|
||||||
AppendString("<img src=\"data:image/png;base64,");
|
AppendString("<img src=\"data:image/png;base64,");
|
||||||
AppendData(logo.p, logo.n);
|
AppendData(logo.p, logo.n);
|
||||||
|
@ -2138,35 +2216,34 @@ img {\n\
|
||||||
r[0] = EscapeHtml(brand, strlen(brand));
|
r[0] = EscapeHtml(brand, strlen(brand));
|
||||||
AppendData(r[0].data, r[0].size);
|
AppendData(r[0].data, r[0].size);
|
||||||
free(r[0].data);
|
free(r[0].data);
|
||||||
AppendString("</h1><hr><pre>\n");
|
AppendString("</h1><hr></header><pre>\n");
|
||||||
w = x = 0;
|
w = x = 0;
|
||||||
n = ZIP_CDIR_RECORDS(zdir);
|
n = ZIP_CDIR_RECORDS(zdir);
|
||||||
CHECK_EQ(kZipCdirHdrMagic, ZIP_CDIR_MAGIC(zdir));
|
CHECK_EQ(kZipCdirHdrMagic, ZIP_CDIR_MAGIC(zdir));
|
||||||
for (cf = ZIP_CDIR_OFFSET(zdir); n--; cf += ZIP_CFILE_HDRSIZE(zmap + cf)) {
|
for (cf = ZIP_CDIR_OFFSET(zdir); n--; cf += ZIP_CFILE_HDRSIZE(zmap + cf)) {
|
||||||
CHECK_EQ(kZipCfileHdrMagic, ZIP_CFILE_MAGIC(zmap + cf));
|
CHECK_EQ(kZipCfileHdrMagic, ZIP_CFILE_MAGIC(zmap + cf));
|
||||||
y = strnwidth(ZIP_CFILE_NAME(zmap + cf), ZIP_CFILE_NAMESIZE(zmap + cf), 0);
|
if (!IsHiddenPath((path = GetAssetPath(cf, &pathlen)))) {
|
||||||
|
y = strwidth(path, 0);
|
||||||
w = MIN(80, MAX(w, y + 2));
|
w = MIN(80, MAX(w, y + 2));
|
||||||
y = ZIP_CFILE_UNCOMPRESSEDSIZE(zmap + cf);
|
y = ZIP_CFILE_UNCOMPRESSEDSIZE(zmap + cf);
|
||||||
y = y ? llog10(y) : 1;
|
y = y ? llog10(y) : 1;
|
||||||
x = MIN(80, MAX(x, y + (y - 1) / 3 + 2));
|
x = MIN(80, MAX(x, y + (y - 1) / 3 + 2));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
n = ZIP_CDIR_RECORDS(zdir);
|
n = ZIP_CDIR_RECORDS(zdir);
|
||||||
for (cf = ZIP_CDIR_OFFSET(zdir); n--; cf += ZIP_CFILE_HDRSIZE(zmap + cf)) {
|
for (cf = ZIP_CDIR_OFFSET(zdir); n--; cf += ZIP_CFILE_HDRSIZE(zmap + cf)) {
|
||||||
CHECK_EQ(kZipCfileHdrMagic, ZIP_CFILE_MAGIC(zmap + cf));
|
CHECK_EQ(kZipCfileHdrMagic, ZIP_CFILE_MAGIC(zmap + cf));
|
||||||
p1 = ZIP_CFILE_NAME(zmap + cf);
|
path = GetAssetPath(cf, &pathlen);
|
||||||
n1 = ZIP_CFILE_NAMESIZE(zmap + cf);
|
if (!IsHiddenPath(path)) {
|
||||||
p2 = malloc(1 + n1);
|
r[0] = EscapeHtml(path, pathlen);
|
||||||
n2 = 1 + n1;
|
r[1] = EscapeUrlPath(path, pathlen);
|
||||||
*p2 = '/';
|
|
||||||
memcpy(p2 + 1, p1, n1);
|
|
||||||
r[0] = EscapeHtml(p2, n2);
|
|
||||||
r[1] = EscapeUrlPath(p2, n2);
|
|
||||||
r[2] = EscapeHtml(r[1].data, r[1].size);
|
r[2] = EscapeHtml(r[1].data, r[1].size);
|
||||||
lastmod = GetLastModifiedZip(zmap + cf);
|
lastmod = GetLastModifiedZip(zmap + cf);
|
||||||
localtime_r(&lastmod, &tm);
|
localtime_r(&lastmod, &tm);
|
||||||
strftime(tb, sizeof(tb), "%Y-%m-%d %H:%M:%S", &tm);
|
strftime(tb, sizeof(tb), "%Y-%m-%d %H:%M:%S", &tm);
|
||||||
if (IsCompressionMethodSupported(ZIP_CFILE_COMPRESSIONMETHOD(zmap + cf)) &&
|
if (IsCompressionMethodSupported(
|
||||||
IsAcceptableHttpRequestPath(p2, n2)) {
|
ZIP_CFILE_COMPRESSIONMETHOD(zmap + cf)) &&
|
||||||
|
IsAcceptableHttpRequestPath(path, pathlen)) {
|
||||||
AppendFmt("<a href=\"%.*s\">%-*.*s</a> %s %4s %,*ld\n", r[2].size,
|
AppendFmt("<a href=\"%.*s\">%-*.*s</a> %s %4s %,*ld\n", r[2].size,
|
||||||
r[2].data, w, r[0].size, r[0].data, tb,
|
r[2].data, w, r[0].size, r[0].data, tb,
|
||||||
DescribeCompressionRatio(rb, cf), x,
|
DescribeCompressionRatio(rb, cf), x,
|
||||||
|
@ -2179,9 +2256,10 @@ img {\n\
|
||||||
free(r[2].data);
|
free(r[2].data);
|
||||||
free(r[1].data);
|
free(r[1].data);
|
||||||
free(r[0].data);
|
free(r[0].data);
|
||||||
free(p2);
|
|
||||||
}
|
}
|
||||||
AppendString("</pre><hr><p>\n");
|
free(path);
|
||||||
|
}
|
||||||
|
AppendString("</pre><footer><hr><p>\n");
|
||||||
if (!unbranded) {
|
if (!unbranded) {
|
||||||
AppendString("\
|
AppendString("\
|
||||||
this listing is for /\n\
|
this listing is for /\n\
|
||||||
|
@ -2197,6 +2275,7 @@ your redbean is ");
|
||||||
}
|
}
|
||||||
w = shared->workers;
|
w = shared->workers;
|
||||||
AppendFmt("currently servicing %,d connection%s\n", w, w == 1 ? "" : "s");
|
AppendFmt("currently servicing %,d connection%s\n", w, w == 1 ? "" : "s");
|
||||||
|
AppendString("</footer>\n");
|
||||||
p = SetStatus(200, "OK");
|
p = SetStatus(200, "OK");
|
||||||
p = AppendCache(p, 0);
|
p = AppendCache(p, 0);
|
||||||
return CommitOutput(p);
|
return CommitOutput(p);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue