// TODO: only works with NanoHTTPD for now sclass HttpFromFileSystem { File baseDir; bool serveDirectoryListings; // default to false *() {} *(File *baseDir) {} *(File *baseDir, bool *serveDirectoryListings) {} O serve(S uri) { LS parts = nempties(splitAtSlash(uri)); // 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); 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)) fail("Path not found: " + uri); } if (isDirectory(f)) ret serveListing(f); else ret serveFile(f); } O serveFile(File f) { ret main serveFile(f, contentTypeForFile(f)); } O serveListing(File dir) { if (!serveDirectoryListings) fail("Can't serve directory listings"); ret "Directory listing" + ul_htmlEncode(listFileNames(dir)); } swappable S contentTypeForFile(File f) { ret or2(extensionToMimeType(fileExtension(f)), binaryMimeType()); } swappable bool validFileName(S name) { ret isValidFileName(name); } }