Warning: session_start(): open(/var/lib/php/sessions/sess_sg0vhvv89kvhd36q0i2isu76kr, O_RDWR) failed: No space left on device (28) in /var/www/tb-usercake/models/config.php on line 51
Warning: session_start(): Failed to read session data: files (path: /var/lib/php/sessions) in /var/www/tb-usercake/models/config.php on line 51
ifdef NoNanoHTTPD
!include once #1028763
endifdef
// TODO: implement If-Modified-Since?
sclass HttpFromFileSystem {
File baseDir;
bool serveDirectoryListings; // default to false
bool serveIndexHTML = true;
bool maxCache; // treat files as immutable
bool debug;
bool sendLastModified = true;
SS headers;
S baseLink = "";
*() {}
*(File *baseDir) {}
*(File *baseDir, bool *serveDirectoryListings) {}
O serve(S uri, SS params, SS headers default null) {
if (eq("1", params.get("maxCache"))) maxCache = true;
this.headers = headers;
ret serve(uri);
}
O serve(S uri) {
S originalURI = uri;
uri = urldecode(uri);
LS parts = nempties(splitAtSlash(uri));
if (baseDir == null) ret serve404("No base directory set");
// process . and ..
for i over parts:
if (eq(parts.get(i), ".")) parts.remove(i);
else if (eq(parts.get(i), ".."))
if (i == 0) fail(".. leading nowhere: " + uri);
else {
parts.remove(i);
parts.remove(--i);
}
if (!all validFileName(parts)) {
print("Parts: " + quoteAll(parts));
fail("Bad path: " + uri);
}
File f = baseDir;
if (!isDirectory(baseDir)) print("Base dir not found: " + f2s(f));
for (S part : parts) {
f = newFile(f, part);
if (!fileExists(f))
ret serve404("Path not found: " + uri);
}
print("Trying to serve: " + f2s(f));
if (isDirectory(f))
ret serveListingOrIndexHTML(uri, f, originalURI);
else
ret serveFile(f);
}
swappable O addHeaders(O response) {
if (maxCache)
ret subBot_maxCacheHeaders(response);
ret response;
}
swappable O serveFile(File f) {
O response;
S range = mapGet(headers, "range");
S ct = contentTypeForFile(f);
if (nempty(range)) {
print("Serving range query " + f + ": " + range);
response = subBot_serveFileRange(f, ct, range);
}
else {
response = main serveFile(f, ct);
if (sendLastModified)
addHeader("Last-Modified", formatDateForLastModifiedHeader(f.lastModified()), response);
}
ret addHeaders(response);
}
O serveListingOrIndexHTML(S uri, File dir, S originalURI) {
if (serveIndexHTML) {
File index = newFile(dir, "index.html");
if (fileExists(index)) {
/*if (nempty(originalURI) && !endsWithSlash(originalURI))
ret subBot_serveRedirect(baseLink + originalURI + "/");*/
ret serveFile(index);
}
}
ret serveListing(uri, dir, originalURI);
}
O serveListing(S uri, File dir, S originalURI) {
if (!serveDirectoryListings) fail("Can't serve directory listings");
// take care of directory listing without trailing slash in URI
S local = addSlashIfNempty(afterLast("/" + uri, '/'));
var names = listFileNames(dir);
sortInPlaceByCalculatedField(names, name -> {
File f = newFile(dir, name);
ret f.isDirectory() ?
pair(false, lower(name))
: pair(true, modificationTime(f));
});
ret postProcessDirListing("Directory listing of " + f2s(dir)
+ ul(map(names, name -> {
File f = newFile(dir, name);
bool isDir = isDirectory(f);
if (isDir) name += "/";
new LS l;
l.add(ahref(/*baseLink +*/ local + name, htmlEncode2(name)));
if (!isDir)
l.add(bracketed(joinNemptiesWithComma(fileInfoHintsWithDate(f))));
if (debug)
l.add(htmlEncode2(bracketed(renderVars(+baseLink, +uri, +local))));
ret hcombine(l);
})));
}
swappable S contentTypeForFile(File f) {
ret or2(extensionToMimeType(fileExtension(f)), binaryMimeType());
}
swappable bool validFileName(S name) { ret isValidFileName(name); }
swappable O postProcessDirListing(S html) { ret html; }
}